123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598 |
- #if UNITY_EDITOR
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEditor;
- using Newtonsoft.Json.Linq;
- using System.IO;
- using System;
- namespace Quixel
- {
- //This class imports the geometry and create the prefabs.
- public class MegascansMeshUtils : MonoBehaviour
- {
- /// <summary>
- /// Import meshes, start from highest LOD and import the chain.
- /// </summary>
- public static void ProcessMeshes(JObject assetJson, string assetFolderPath, bool highpoly, bool hasVariations, PrefabData prefabData)
- {
- try
- {
- bool createPrefabs = EditorPrefs.GetBool("QuixelDefaultSetupPrefabs", true);
- bool importLODs = EditorPrefs.GetBool("QuixelDefaultImportLODs", true);
- bool setupLODs = EditorPrefs.GetBool("QuixelDefaultSetupLOD", true);
- prefabData.setupLODs = (importLODs && setupLODs); //Only do LOD setup if lower lods were imported and LOD grouping is enabled.
- //get mesh components from the current object. Also, meshComps.Count can give us the number of variations ;)
- JArray meshComps = (JArray)assetJson["meshList"];
- JArray lodList = (JArray)assetJson["lodList"];
- string activeLOD = (string)assetJson["activeLOD"];
- string minLOD = (string)assetJson["minLOD"];
- string modelsFolderPath = MegascansUtilities.ValidateFolderCreate(assetFolderPath, "Models");
- if (hasVariations)
- {
- List<List<string>> importedGeometryPaths3DPlant = new List<List<string>>();
- for (int i = 1; i <= meshComps.Count; i++)
- {
- List<string> importedGeometryPaths = new List<string>();
- bool lodMatched = false; // This flag helps to import the lower lods once the active lod is found.
- foreach (JObject mesh in lodList)
- {
- if ((int)mesh["variation"] == i)
- {
- string currentLOD = (string)mesh["lod"];
- if (lodMatched || currentLOD == activeLOD || highpoly)
- {
- lodMatched = true;
- if ((currentLOD == "high") && !highpoly)
- {
- continue;
- }
- //get the path of the highest LOD to be imported.
- string sourcePath = (string)mesh["path"];
- string destPath = Path.Combine(modelsFolderPath, (string)mesh["nameOverride"]);
- ImportMesh(sourcePath, destPath);
- importedGeometryPaths.Add(destPath);
- if(!importLODs)
- {
- break;
- }
- }
- }
- }
- importedGeometryPaths3DPlant.Add(importedGeometryPaths);
- }
- prefabData.importedGeometryPaths3DPlant = importedGeometryPaths3DPlant;
- if(createPrefabs)
- CreatePrefab3DPlant(prefabData);
- }
- else
- {
- List<string> importedGeometryPaths3D = new List<string>();
- bool lodMatched = false; // This flag helps to import the lower lods once the active lod is found.
- foreach (JObject mesh in lodList)
- {
- string currentLOD = (string)mesh["lod"];
- if (lodMatched || (currentLOD == activeLOD) || highpoly)
- {
- lodMatched = true;
- if ((currentLOD == "high") && !highpoly)
- {
- continue;
- }
- //get the path of the highest LOD to be imported.
- string sourcePath = (string)mesh["path"];
- string destPath = Path.Combine(modelsFolderPath, (string)mesh["nameOverride"]);
- ImportMesh(sourcePath, destPath);
- importedGeometryPaths3D.Add(destPath);
- if (!importLODs)
- {
- break;
- }
- }
- }
- prefabData.importedGeometryPaths3D = importedGeometryPaths3D;
- if (createPrefabs)
- {
- if (MegascansUtilities.isScatterAsset(assetJson, importedGeometryPaths3D))
- {
- CreatePrefabsScatter(prefabData);
- }
- else
- {
- CreatePrefab3D(prefabData);
- }
- }
- }
- }
- catch (Exception ex)
- {
- Debug.Log("Exception::MegascansMeshUtils::Processing Meshes:: " + ex.ToString());
- MegascansUtilities.HideProgressBar();
- }
- }
- static void ImportMesh(string sourcePath, string destPath)
- {
- MegascansUtilities.UpdateProgressBar(1.0f, "Importing Megascans Asset", "Importing Mesh...");
- MegascansUtilities.CopyFileToProject(sourcePath, destPath);
- }
- /// <summary>
- /// Generates prefabs from imported meshes.
- /// Used for normal 3D assets
- /// </summary>
- public static void CreatePrefab3D(PrefabData prefabData)
- {
- try {
- string prefabPath = MegascansUtilities.ValidateFolderCreate(prefabData.assetPath, "Prefabs");
- string prefabName = prefabData.modelNamingConvention;
- //Setting up prefab gameobject
- GameObject prefabGameObject = new GameObject();
- prefabGameObject.name = prefabName;
- prefabGameObject.isStatic = true;
- if (prefabData.setupLODs)
- {
- prefabGameObject.AddComponent<LODGroup>();
- prefabGameObject.GetComponent<LODGroup>().fadeMode = (LODFadeMode)prefabData.lodFadeMode; //Casting lod fade mode to enum.
- prefabGameObject.GetComponent<LODGroup>().animateCrossFading = true;
- }
- List<LOD> lodsForPrefab = new List<LOD>();
- int numberOfFiles = prefabData.importedGeometryPaths3D.Count;
- List<float> lodHeights = MegascansUtilities.getLODHeightList(numberOfFiles);
- //Instantiate all the meshes in the scene, add them to the material/collider to them.
- for (int x = 0; (x < numberOfFiles && x < 8); x++)
- {
- UnityEngine.Object loadedGeometry = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(prefabData.importedGeometryPaths3D[x]);
- //Highpoly mesh check.
- if (loadedGeometry.name.ToLower().Contains("highpoly") && !prefabData.highpoly)
- {
- continue;
- }
- GameObject geometryObject = Instantiate(loadedGeometry) as GameObject;
- Renderer[] r;
- //Parent all the objects to the prefab game object.
- if (geometryObject.transform.childCount > 0 && !prefabData.isAlembic)
- {
- r = new Renderer[geometryObject.transform.childCount];
- for (int j = 0; j < geometryObject.transform.childCount; ++j)
- {
- //Parent the child gameobject (geometry) to the prefab game object.
- GameObject geometryChildObject = geometryObject.transform.GetChild(j).gameObject; //Cache a reference to the child gameobject of the geometry.
- geometryChildObject.transform.parent = prefabGameObject.transform;
- geometryChildObject.transform.localPosition = Vector3.zero;
- geometryChildObject.name = geometryChildObject.name.Replace("(Clone)", "");
- r[j] = geometryChildObject.GetComponentInChildren<Renderer>();
- }
- //Destroy the empty parent container which was holding the meshes.
- DestroyImmediate(geometryObject);
- }
- else if (prefabData.isAlembic) //if the instantiated mesh is an alembic asset.
- {
- //Parent the child gameobject (geometry) to the prefab game object.
- geometryObject.transform.parent = prefabGameObject.transform;
- geometryObject.transform.localPosition = Vector3.zero;
- geometryObject.name = geometryObject.name.Replace("(Clone)", "");
- r = geometryObject.GetComponentsInChildren<Renderer>();
- }
- else //if the instantiated mesh does not have any children
- {
- //Parent the child gameobject (geometry) to the prefab game object.
- geometryObject.transform.parent = prefabGameObject.transform;
- geometryObject.transform.localPosition = Vector3.zero;
- geometryObject.name = geometryObject.name.Replace("(Clone)", "");
- r = geometryObject.GetComponentsInChildren<Renderer>();
- }
- foreach (Renderer ren in r)
- {
- ren.material = prefabData.finalMat;
- //Apply collision
- if (prefabData.setupCollision)
- ren.gameObject.AddComponent<MeshCollider>().sharedMesh = ren.gameObject.GetComponent<MeshFilter>().sharedMesh;
- }
- if (prefabData.setupLODs)
- {
- lodsForPrefab.Add(new LOD(lodHeights[0], r));
- lodHeights.RemoveAt(0);
- } else //We only set the prefab with 1 LOD if setup LODs is unchecked.
- break;
- }
- //Set LODs in the LOD group
- if (prefabData.setupLODs)
- {
- prefabGameObject.GetComponent<LODGroup>().SetLODs(lodsForPrefab.ToArray());
- prefabGameObject.GetComponent<LODGroup>().RecalculateBounds();
- }
- //Prefab saving
- string prefLocation = prefabPath + "/" + prefabName + ".prefab";
- prefLocation = prefLocation.Replace("(Clone)", "");
- SavePrefab(prefabGameObject, prefLocation, prefabData.addAssetToScene);
- }
- catch (Exception ex)
- {
- Debug.Log("Exception::MegascansMeshUtils::3D Asset Prefab:: " + ex.ToString());
- MegascansUtilities.HideProgressBar();
- }
- }
- /// <summary>
- /// Creates prefabs from the newer assets on bridge, has an option for billboard materials on plants.
- /// </summary>
- /// <param name="hasBillboard"></param>
- /// <returns></returns>
- public static void CreatePrefab3DPlant(PrefabData prefabData)
- {
- try
- {
- string prefabPath = MegascansUtilities.ValidateFolderCreate(prefabData.assetPath, "Prefabs");
- List<GameObject> prefabObjects = new List<GameObject>();
- for (int i = 0; i < prefabData.importedGeometryPaths3DPlant.Count; i++)
- {
- string prefabName = prefabData.modelNamingConvention + "_Var" + (i + 1).ToString();
- //Setting up prefab gameobject
- GameObject prefabGameObject = new GameObject();
- prefabGameObject.name = prefabName;
- prefabGameObject.isStatic = true;
- if (prefabData.setupLODs)
- {
- prefabGameObject.AddComponent<LODGroup>();
- prefabGameObject.GetComponent<LODGroup>().fadeMode = (LODFadeMode)prefabData.lodFadeMode; //Casting lod fade mode to enum.
- prefabGameObject.GetComponent<LODGroup>().animateCrossFading = true;
- }
- List<LOD> lodsForPrefab = new List<LOD>();
- int numberOfFiles = prefabData.importedGeometryPaths3DPlant[i].Count;
- List<float> lodHeights = MegascansUtilities.getLODHeightList(numberOfFiles);
- //Instantiate all the meshes in the scene, add them to the material/collider to them.
- for (int x = 0; (x < numberOfFiles && x < 8); x++)
- {
- UnityEngine.Object loadedGeometry = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(prefabData.importedGeometryPaths3DPlant[i][x]);
- //Highpoly mesh check.
- if (loadedGeometry.name.ToLower().Contains("highpoly") && !prefabData.highpoly)
- {
- continue;
- }
- GameObject geometryObject = Instantiate(loadedGeometry) as GameObject;
- Renderer[] r;
- //Parent all the objects to the prefab game object.
- if (geometryObject.transform.childCount > 0 && !prefabData.isAlembic)
- {
- r = new Renderer[geometryObject.transform.childCount];
- for (int j = 0; j < geometryObject.transform.childCount; ++j)
- {
- //Parent the child gameobject (geometry) to the prefab game object.
- GameObject geometryChildObject = geometryObject.transform.GetChild(j).gameObject; //Cache a reference to the child gameobject of the geometry.
- geometryChildObject.transform.parent = prefabGameObject.transform;
- geometryChildObject.transform.localPosition = Vector3.zero;
- geometryChildObject.name = geometryChildObject.name.Replace("(Clone)", "");
- r[j] = geometryChildObject.GetComponent<Renderer>();
- }
- //Destroy the empty parent container which was holding the meshes.
- DestroyImmediate(geometryObject);
- }
- else if (prefabData.isAlembic) //if the instantiated mesh is an alembic asset.
- {
- //Parent the child gameobject (geometry) to the prefab game object.
- geometryObject.transform.parent = prefabGameObject.transform;
- geometryObject.transform.localPosition = Vector3.zero;
- geometryObject.name = geometryObject.name.Replace("(Clone)", "");
- r = geometryObject.GetComponentsInChildren<Renderer>();
- }
- else //if the instantiated mesh does not have any children
- {
- r = new Renderer[1];
- //Parent the child gameobject (geometry) to the prefab game object.
- geometryObject.transform.parent = prefabGameObject.transform;
- geometryObject.transform.localPosition = Vector3.zero;
- geometryObject.name = geometryObject.name.Replace("(Clone)", "");
- r[0] = geometryObject.GetComponent<Renderer>();
- }
- foreach (Renderer ren in r)
- {
- ren.material = prefabData.finalMat;
- //Billboard material application
- if (prefabData.hasBillboardLOD && x == (numberOfFiles - 1))
- {
- ren.material = prefabData.billboardMat;
- }
- //Apply collision
- if (prefabData.setupCollision)
- ren.gameObject.AddComponent<MeshCollider>().sharedMesh = ren.gameObject.GetComponent<MeshFilter>().sharedMesh;
- }
- if (prefabData.setupLODs)
- {
- lodsForPrefab.Add(new LOD(lodHeights[0], r));
- lodHeights.RemoveAt(0);
- }
- else
- break;
- }
- //Set LODs in the LOD group
- if (prefabData.setupLODs)
- {
- prefabGameObject.GetComponent<LODGroup>().SetLODs(lodsForPrefab.ToArray());
- prefabGameObject.GetComponent<LODGroup>().RecalculateBounds();
- }
- //Prefab saving
- string prefLocation = prefabPath + "/" + prefabName + ".prefab";
- prefLocation = prefLocation.Replace("(Clone)", "");
- GameObject prefabObject = SavePrefab(prefabGameObject, prefLocation, prefabData.addAssetToScene);
- if (prefabObject)
- prefabObjects.Add(prefabObject);
- }
- //Setting up variation holder gameobject
- if (prefabData.addAssetToScene)
- {
- GameObject plantsParent = new GameObject(prefabData.assetName);
- plantsParent.isStatic = true;
- foreach (GameObject variation in prefabObjects)
- {
- variation.transform.parent = plantsParent.transform;
- }
- }
- }
- catch (Exception ex)
- {
- Debug.Log("Exception::MegascansMeshUtils::3D Plant Prefab:: " + ex.ToString());
- MegascansUtilities.HideProgressBar();
- }
- }
- /// <summary>
- /// Creates prefabs for the 3D Scatter assets.
- /// </summary>
- /// <param name="hasBillboard"></param>
- /// <returns></returns>
- public static void CreatePrefabsScatter(PrefabData prefabData)
- {
- try
- {
- string prefabPath = MegascansUtilities.ValidateFolderCreate(prefabData.assetPath, "Prefabs");
- int numberOfVariations = MegascansUtilities.GetMeshChildrenCount(prefabData.importedGeometryPaths3D);
- List<GameObject> prefabObjects = new List<GameObject>();
- for (int i = 0; i < numberOfVariations; i++)
- {
- string prefabName = prefabData.modelNamingConvention + "_Var" + (i + 1).ToString();
- //Setting up prefab gameobject
- GameObject prefabGameObject = new GameObject();
- prefabGameObject.name = prefabName;
- prefabGameObject.isStatic = true;
- if (prefabData.setupLODs)
- {
- prefabGameObject.AddComponent<LODGroup>();
- prefabGameObject.GetComponent<LODGroup>().fadeMode = (LODFadeMode)prefabData.lodFadeMode; //Casting lod fade mode to enum.
- prefabGameObject.GetComponent<LODGroup>().animateCrossFading = true;
- }
- List<LOD> lodsForPrefab = new List<LOD>();
- int numberOfFiles = prefabData.importedGeometryPaths3D.Count;
- List<float> lodHeights = MegascansUtilities.getLODHeightList(numberOfFiles);
- //Instantiate all the meshes in the scene, add them to the material/collider to them.
- for (int x = 0; (x < numberOfFiles && x < 8); x++)
- {
- UnityEngine.Object loadedGeometry = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(prefabData.importedGeometryPaths3D[x]);
- //Highpoly mesh check.
- if (loadedGeometry.name.ToLower().Contains("highpoly") && !prefabData.highpoly)
- {
- continue;
- }
- GameObject geometryObject = Instantiate(loadedGeometry) as GameObject;
- Renderer[] r;
- if (prefabData.isAlembic) //if the instantiated mesh is an alembic asset.
- {
- //Get all variations in a LOD
- List<Transform> varsInLOD = new List<Transform>();
- foreach (Transform var in geometryObject.transform)
- {
- varsInLOD.Add(var);
- }
- //Delete all the other variations in the LOD object
- for (int y = 0; y < varsInLOD.Count; y++)
- {
- //If variation does not match one currently being processed.
- if (y != i)
- {
- DestroyImmediate(varsInLOD[y].gameObject);
- }
- }
- //Parent the child gameobject (geometry) to the prefab game object.
- geometryObject.transform.parent = prefabGameObject.transform;
- geometryObject.transform.localPosition = Vector3.zero;
- geometryObject.name = geometryObject.name.Replace("(Clone)", "");
- r = geometryObject.GetComponentsInChildren<Renderer>();
- }
- else//if the instantiated mesh is a scatter type asset.
- {
- //Get all variations in a LOD
- List<Transform> varsInLOD = new List<Transform>();
- foreach (Transform var in geometryObject.transform)
- {
- varsInLOD.Add(var);
- }
- //Delete all the other variations in the LOD object
- for(int y = 0; y < varsInLOD.Count; y++)
- {
- //If variation does not match one currently being processed.
- if(y!=i)
- {
- DestroyImmediate(varsInLOD[y].gameObject);
- }
- }
- //Parent the child gameobject (geometry) to the prefab game object.
- geometryObject.transform.parent = prefabGameObject.transform;
- geometryObject.transform.localPosition = Vector3.zero;
- geometryObject.name = geometryObject.name.Replace("(Clone)", "");
- r = geometryObject.GetComponentsInChildren<Renderer>();
- }
- foreach (Renderer ren in r)
- {
- ren.material = prefabData.finalMat;
- //Apply collision
- if (prefabData.setupCollision)
- ren.gameObject.AddComponent<MeshCollider>().sharedMesh = ren.gameObject.GetComponent<MeshFilter>().sharedMesh;
- }
- if (prefabData.setupLODs)
- {
- lodsForPrefab.Add(new LOD(lodHeights[0], r));
- lodHeights.RemoveAt(0);
- }
- else
- break;
- }
- //Set LODs in the LOD group
- if (prefabData.setupLODs)
- {
- prefabGameObject.GetComponent<LODGroup>().SetLODs(lodsForPrefab.ToArray());
- prefabGameObject.GetComponent<LODGroup>().RecalculateBounds();
- }
- //Prefab saving
- string prefLocation = prefabPath + "/" + prefabName + ".prefab";
- prefLocation = prefLocation.Replace("(Clone)", "");
- GameObject prefabObject = SavePrefab(prefabGameObject, prefLocation, prefabData.addAssetToScene);
- if (prefabObject)
- prefabObjects.Add(prefabObject);
- }
- //Setting up variation holder gameobject
- if (prefabData.addAssetToScene)
- {
- GameObject scatterParent = new GameObject(prefabData.assetName);
- scatterParent.isStatic = true;
- foreach (GameObject variation in prefabObjects)
- {
- variation.transform.parent = scatterParent.transform;
- }
- }
- }
- catch (Exception ex)
- {
- Debug.Log("Exception::MegascansMeshUtils::3D Asset Prefab:: " + ex.ToString());
- MegascansUtilities.HideProgressBar();
- }
- }
- static GameObject SavePrefab(GameObject prefabGo, string savePath, bool addAssetToScene = false)
- {
- try
- {
- //Set all children objects of the prefab to static
- Transform[] allChildren = prefabGo.GetComponentsInChildren<Transform>();
- foreach (Transform child in allChildren)
- {
- child.gameObject.isStatic = true;
- }
- GameObject newPrefabObject = prefabGo;
- MegascansUtilities.UpdateProgressBar(1.0f, "Importing Megascans Asset", "Creating Prefab...");
- #if UNITY_5 || UNITY_2017 || UNITY_2018
- UnityEngine.Object existingPrefab = AssetDatabase.LoadAssetAtPath(savePath, typeof(UnityEngine.Object));
- if (!existingPrefab)
- PrefabUtility.CreatePrefab(savePath, prefabGo);
- else
- PrefabUtility.ReplacePrefab(prefabGo, existingPrefab, ReplacePrefabOptions.ReplaceNameBased);
- #else
- PrefabUtility.SaveAsPrefabAsset(prefabGo, savePath);
- #endif
- DestroyImmediate(prefabGo);
- if (addAssetToScene)
- {
- UnityEngine.Object prefabObject = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(savePath);
- newPrefabObject = (GameObject)PrefabUtility.InstantiatePrefab(prefabObject);
- newPrefabObject.isStatic = true;
- }
- return newPrefabObject;
- }
- catch (Exception ex)
- {
- Debug.Log("Exception::MegascansMeshUtils::Saving Prefab:: " + ex.ToString());
- MegascansUtilities.HideProgressBar();
- return null;
- }
- }
- public static bool ContainsLowestLOD(JArray lodList, string minLOD, string activeLOD)
- {
- bool importLODs = EditorPrefs.GetBool("QuixelDefaultImportLODs", true);
- if (importLODs)
- {
- for (int i = 0; i < lodList.Count; i++)
- {
- JObject meshData = (JObject)lodList[i];
- if ((string)meshData["lod"] == minLOD)
- return true;
- }
- return false;
- } else
- {
- return (activeLOD.ToLower() == minLOD.ToLower());
- }
- }
- }
- public struct PrefabData
- {
- public string assetPath;
- public string assetName;
- public string modelNamingConvention;
- public int lodFadeMode;
- public bool highpoly;
- public bool addAssetToScene;
- public bool setupCollision;
- public bool hasBillboardLOD;
- public bool isAlembic;
- public bool isScatterAsset;
- public bool setupLODs;
- public Material finalMat;
- public Material billboardMat;
- public List<string> importedGeometryPaths3D;
- public List<List<string>> importedGeometryPaths3DPlant;
- public PrefabData(string assetPath, string assetName, string modelNamingConvention, int lodFadeMode, bool highpoly, bool addAssetToScene, bool setupCollision, bool hasBillboardLOD, bool isAlembic, bool isScatterAsset, bool setupLODs, Material finalMat, Material billboardMat, List<string> importedGeometryPaths3D, List<List<string>> importedGeometryPaths3DPlant)
- {
- this.assetPath = assetPath;
- this.assetName = assetName;
- this.modelNamingConvention = modelNamingConvention;
- this.lodFadeMode = lodFadeMode;
- this.highpoly = highpoly;
- this.addAssetToScene = addAssetToScene;
- this.setupCollision = setupCollision;
- this.hasBillboardLOD = hasBillboardLOD;
- this.isAlembic = isAlembic;
- this.isScatterAsset = isScatterAsset;
- this.setupLODs = setupLODs;
- this.finalMat = finalMat;
- this.billboardMat = billboardMat;
- this.importedGeometryPaths3D = importedGeometryPaths3D;
- this.importedGeometryPaths3DPlant = importedGeometryPaths3DPlant;
- }
- }
- }
- #endif
|