123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412 |
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEditor;
- using System;
- using System.Linq;
- #if UNITY_EDITOR
- namespace Quixel
- {
- public class MegascansTerrainTools
- {
- /*
- (Verify that the pipeline is HDRP.)
- * *******************************************************************************
- * ********************** Unity 2018.1 and 2018.2 ********************************
- * *******************************************************************************
- Terrain material blend setup steps:
- 1. Get selected materials and make a terrain LayeredLit Material.
- 2. Set Splat Prop types for the terrain.
- 3. Set created materail to the terrain.
- 4. Enable splat maps for the terrain.
- 5. Set Layer Mask property of the terrain material to use Splat Alpha Map.
- 6. Voila start painting!
- * *******************************************************************************
- * ********************** Unity 2018.3 onwards ***********************************
- * *******************************************************************************
- * Terrain material blend setup steps:
- 1. Get selected materials and make Terrain Layers from them.
- 2. Assign newly created terrain layers to terrain data.
- 3. Voila start painting!
- */
- static int maxMaterialAllowed = 4;
- public static void SetupTerrain()
- {
- string materialName = EditorPrefs.GetString("QuixelDefaultMaterialName", "Terrain Material");
- string materialPath = EditorPrefs.GetString("QuixelDefaultMaterialPath", "Quixel/");
- string tilingNumber = EditorPrefs.GetString("QuixelDefaultTiling", "10");
- string[] versionParts = Application.unityVersion.Split('.');
- int majorVersion = int.Parse(versionParts[0]);
- if (majorVersion < 2018)
- {
- Debug.Log("This Unity version doesn't support this feature.");
- return;
- }
- else
- {
- float tiling;
- try
- {
- tiling = float.Parse(tilingNumber);
- }
- catch (Exception ex)
- {
- Debug.Log("Exception: " + ex.ToString());
- tiling = 1f;
- }
- maxMaterialAllowed = MegascansUtilities.isLegacy() ? 4 : 8;
- List<Material> sourceMaterials = new List<Material>();
- Terrain terrain = null;
- try
- {
- //Get currently highlighted materials in the project window.
- sourceMaterials = GetSelectedMaterialsInProjectHierarchy();
- //Verify two or more materails were seleted.
- if (sourceMaterials.Count < 2 && MegascansUtilities.isLegacy())
- {
- Debug.Log("Not enough materials to create a blend material. Please select more materials.");
- return;
- }
- //Get selected terrain in the scene view.
- terrain = getCurrentlySelectedTerrain();
- //Verify a terrain is selected.
- if (terrain == null)
- {
- Debug.Log("No terrain selected. Please select a terrain.");
- //return;
- }
- }
- catch (Exception ex)
- {
- Debug.Log("Error getting select terrain/materials.");
- Debug.Log(ex);
- }
- if (MegascansUtilities.isLegacy())
- {
- try
- {
- //Set up the material here.
- Material terrainMaterial = SetupTerrainMaterialDeprecated(sourceMaterials, materialPath, materialName, tiling);
- //Get terrain data for splat maps.
- TerrainData terrainData = terrain.terrainData;
- //Get the textures from source materials to add to the painting.
- if (terrainData)
- {
- #pragma warning disable
- terrainData.splatPrototypes = getMaterialTexturesForSplatMap(sourceMaterials, tiling);
- }
- terrain.materialType = Terrain.MaterialType.Custom;
- terrain.materialTemplate = terrainMaterial;
- EnableSplatmaps(terrainData);
- Texture2D alphaMap = terrainData.alphamapTextures[0];
- terrainMaterial.SetTexture("_LayerMaskMap", alphaMap);
- Debug.Log("Terrain blend material successfully created!");
- }
- catch (Exception ex)
- {
- Debug.Log("Error Generating terrain blend material!");
- Debug.Log(ex);
- }
- }
- else
- {
- #if UNITY_2018_3 || UNITY_2018_4 || UNITY_2019 || UNITY_2020 || UNITY_2021
- //Create the material here.
- //Material terrainMaterial = SetupTerrainMaterial(materialPath, materialName);
- List<TerrainLayer> terrainLayers = new List<TerrainLayer>();
- foreach (TerrainLayer tl in terrain.terrainData.terrainLayers)
- {
- terrainLayers.Add(tl);
- }
- // Unity's terrain system uses the second terrain layer as default material on terrain.
- // To counter this we swap the position of the materials in our list.
- if (sourceMaterials.Count > 1 && terrainLayers.Count == 0)
- {
- Material tempMat = sourceMaterials[0];
- sourceMaterials[0] = sourceMaterials[1];
- sourceMaterials[1] = tempMat;
- }
- foreach (Material mat in sourceMaterials)
- {
- if (terrainLayers.Count <= 8)
- {
- terrainLayers.Add(createTerrainLayer(mat, tiling));
- }
- }
- if (terrainLayers.Count > 0)
- {
- terrain.terrainData.terrainLayers = terrainLayers.ToArray();
- }
- #endif
- }
- }
- }
- public static Material CreateMaterial(string mPath, string name, string shaderName)
- {
- string path = MegascansUtilities.FixPath(mPath);
- /// Unity doesn't allow you to create objects in directories which don't exist.
- /// So in this function, we create any and all necessary subdirectories that are required.
- /// We return the final subdirectory, which is used later in the asset creation too.
- //first, create the user specified path from the importer settings.
- string[] pathParts = MegascansUtilities.FixSlashes(path).Split('/');
- string defPath = "Assets";
- if (pathParts.Length > 0)
- {
- for (int i = 0; i < pathParts.Length; ++i)
- {
- defPath = MegascansUtilities.ValidateFolderCreate(defPath, pathParts[i]);
- }
- }
- defPath = defPath + "/" + name + ".mat";
- Material terrainMaterial = new Material(Shader.Find(shaderName));
- AssetDatabase.CreateAsset(terrainMaterial, defPath);
- AssetDatabase.Refresh();
- return terrainMaterial;
- }
- //This method sets the right parameters depending upon the selected settings.
- public static Material SetupTerrainMaterial(string materialPath, string materialName)
- {
- Material terrainMaterial = CreateMaterial(materialPath, materialName, "HDRenderPipeline/TerrainLit");
- terrainMaterial.enableInstancing = true;
- return terrainMaterial;
- }
- public static Material SetupTerrainMaterialDeprecated(List<Material> sourceMaterials, string materialPath, string materialName, float tiling)
- {
- int numberOfLayers = Mathf.Clamp(sourceMaterials.Count + 1, 2, 4);
- Material terrainMaterial = CreateMaterial(materialPath, materialName, "HDRenderPipeline/LayeredLit");
- terrainMaterial.SetFloat("_LayerCount", numberOfLayers);
- terrainMaterial.EnableKeyword("_LAYEREDLIT_" + numberOfLayers.ToString() + "_LAYERS");
- numberOfLayers--;
- if (numberOfLayers > 3)
- {
- SetFloatsAndTexturesDeprecated(terrainMaterial, sourceMaterials[3], "0", tiling);
- SetFloatsAndTexturesDeprecated(terrainMaterial, sourceMaterials[0], "1", tiling);
- SetFloatsAndTexturesDeprecated(terrainMaterial, sourceMaterials[1], "2", tiling);
- SetFloatsAndTexturesDeprecated(terrainMaterial, sourceMaterials[2], "3", tiling);
- }
- else if (numberOfLayers > 2)
- {
- SetFloatsAndTexturesDeprecated(terrainMaterial, sourceMaterials[2], "0", tiling);
- SetFloatsAndTexturesDeprecated(terrainMaterial, sourceMaterials[0], "1", tiling);
- SetFloatsAndTexturesDeprecated(terrainMaterial, sourceMaterials[1], "2", tiling);
- SetFloatsAndTexturesDeprecated(terrainMaterial, sourceMaterials[2], "3", tiling);
- }
- else if (numberOfLayers > 1)
- {
- SetFloatsAndTexturesDeprecated(terrainMaterial, sourceMaterials[1], "0", tiling);
- SetFloatsAndTexturesDeprecated(terrainMaterial, sourceMaterials[0], "1", tiling);
- SetFloatsAndTexturesDeprecated(terrainMaterial, sourceMaterials[1], "2", tiling);
- }
- return terrainMaterial;
- }
- public static void SetFloatsAndTexturesDeprecated(Material terrainMaterial, Material sourceMaterial, string suffix, float tiling)
- {
- terrainMaterial.EnableKeyword("_MASKMAP" + suffix);
- terrainMaterial.EnableKeyword("_NORMALMAP" + suffix);
- terrainMaterial.EnableKeyword("_NORMALMAP_TANGENT_SPACE" + suffix);
- terrainMaterial.EnableKeyword("_MASKMAP" + suffix);
- terrainMaterial.SetTexture("_BaseColorMap" + suffix, sourceMaterial.mainTexture);
- terrainMaterial.SetTexture("_MaskMap" + suffix, sourceMaterial.GetTexture("_MaskMap"));
- terrainMaterial.SetTexture("_NormalMap" + suffix, sourceMaterial.GetTexture("_NormalMap"));
- terrainMaterial.SetFloat("_NormalMapSpace" + suffix, 0f);
- terrainMaterial.SetFloat("_Metallic" + suffix, 1f);
- terrainMaterial.SetTextureScale("_BaseColorMap" + suffix, new Vector2(tiling, tiling));
- terrainMaterial.SetTextureScale("_MaskMap" + suffix, new Vector2(tiling, tiling));
- terrainMaterial.SetTextureScale("_NormalMap" + suffix, new Vector2(tiling, tiling));
- }
- public static List<Material> GetSelectedMaterialsInProjectHierarchy()
- {
- List<Material> selectedMaterials = new List<Material>();
- List<string> selectedMaterialPaths = new List<string>();
- List<UnityEngine.Object> selection = new List<UnityEngine.Object>();
- foreach (UnityEngine.Object obj in Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.Assets))
- {
- if (obj.GetType() == typeof(Material) && selectedMaterials.Count <= maxMaterialAllowed)
- {
- selectedMaterials.Add((Material)obj);
- }
- else
- {
- selection.Add(obj);
- }
- }
- List<string> selectedFolders = MegascansUtilities.GetSelectedFolders(selection);
- foreach (string folder in selectedFolders)
- {
- selectedMaterialPaths = selectedMaterialPaths.Concat(MegascansUtilities.GetFiles(folder, ".mat")).ToList();
- }
- foreach (string mPath in selectedMaterialPaths)
- {
- Material mat = (Material)AssetDatabase.LoadAssetAtPath(mPath, typeof(Material));
- if (mat != null && selectedMaterials.Count <= maxMaterialAllowed) //4 is the max number of layers currently allowed in the HDRenderPipeline/LayeredLit shader.
- {
- selectedMaterials.Add(mat);
- }
- }
- return selectedMaterials;
- }
- public static SplatPrototype[] getMaterialTexturesForSplatMap(List<Material> materials, float tiling)
- {
- SplatPrototype[] splatPropsTypes = new SplatPrototype[materials.Count];
- for (int i = 0; i < materials.Count; i++)
- {
- SplatPrototype prop = new SplatPrototype();
- prop.texture = (Texture2D)materials[i].mainTexture;
- prop.normalMap = (Texture2D)materials[i].GetTexture("_NormalMap");
- prop.tileSize = new Vector2(tiling, tiling);
- splatPropsTypes[i] = prop;
- }
- return splatPropsTypes;
- }
- public static Terrain getCurrentlySelectedTerrain()
- {
- foreach (UnityEngine.Object obj in Selection.objects)
- {
- if (obj.GetType() == typeof(GameObject))
- {
- GameObject terrain = (GameObject)obj;
- if (terrain.GetComponent<Terrain>())
- {
- return terrain.GetComponent<Terrain>();
- }
- }
- }
- return null;
- }
- public static void EnableSplatmaps(TerrainData terrainData)
- {
- UnityEngine.Object[] data = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(terrainData));
- foreach (UnityEngine.Object o in data)
- {
- if (o is Texture2D)
- {
- (o as Texture2D).hideFlags = HideFlags.None;
- AssetDatabase.SaveAssets();
- AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(o));
- }
- }
- }
- #if UNITY_2018_3 || UNITY_2018_4 || UNITY_2019 || UNITY_2020 || UNITY_2021
- public static TerrainLayer createTerrainLayer(Material mat, float tiling)
- {
- TerrainLayer terrainLayer = new TerrainLayer();
- string path = AssetDatabase.GetAssetPath(mat);
- path = path.Replace(".mat", ".terrainlayer");
- AssetDatabase.CreateAsset(terrainLayer, path);
- AssetDatabase.Refresh();
- terrainLayer.diffuseTexture = (Texture2D)mat.mainTexture;
- //attempt to auto-detect a settings file for Lightweight or HD pipelines
- switch (MegascansUtilities.getCurrentPipeline())
- {
- case Pipeline.HDRP:
- terrainLayer.normalMapTexture = (Texture2D)mat.GetTexture("_NormalMap");
- if (mat.GetFloat("_MaterialID") == 4)
- {
- terrainLayer.maskMapTexture = (Texture2D)mat.GetTexture("_SpecularColorMap");
- terrainLayer.metallic = 1.0f;
- }
- else if (mat.GetFloat("_MaterialID") == 1)
- {
- terrainLayer.maskMapTexture = (Texture2D)mat.GetTexture("_MaskMap");
- terrainLayer.specular = new Color(1.0f, 1.0f, 1.0f);
- }
- break;
- case Pipeline.LWRP:
- terrainLayer.normalMapTexture = (Texture2D)mat.GetTexture("_BumpMap");
- if (mat.GetFloat("_WorkflowMode") == 1)
- {
- terrainLayer.maskMapTexture = (Texture2D)mat.GetTexture("_MetallicGlossMap");
- terrainLayer.specular = new Color(1.0f, 1.0f, 1.0f);
- }
- else
- {
- terrainLayer.maskMapTexture = (Texture2D)mat.GetTexture("_SpecGlossMap");
- terrainLayer.metallic = 1.0f;
- }
- break;
- case Pipeline.Standard:
- terrainLayer.normalMapTexture = (Texture2D)mat.GetTexture("_BumpMap");
- if (mat.shader.ToString() == "Standard (Specular setup)")
- {
- terrainLayer.maskMapTexture = (Texture2D)mat.GetTexture("_SpecGlossMap");
- terrainLayer.metallic = 1.0f;
- }
- else
- {
- terrainLayer.maskMapTexture = (Texture2D)mat.GetTexture("_MetallicGlossMap");
- terrainLayer.specular = new Color(1.0f, 1.0f, 1.0f);
- }
- break;
- }
- terrainLayer.tileSize = new Vector2(tiling, tiling);
- return terrainLayer;
- }
- public static void CreateTerrainLayerFromMat()
- {
- try {
- Material selectedMat = MegascansUtilities.GetSelectedMaterial();
- if (!selectedMat)
- return;
- Debug.Log("Here");
- createTerrainLayer(selectedMat, 1f);
- Debug.Log("Successfully created the terrain layer.");
- }
- catch (Exception ex)
- {
- Debug.Log("Exception::MegascansImageUtils::Flip Green Channel:: " + ex.ToString());
- MegascansUtilities.HideProgressBar();
- }
- }
- #endif
- }
- }
- #endif
|