public void EditorCreatePreview() { if (DataName == "") { MTLog.LogError("data should have a name"); return; } try { Transform[] lodParent = new Transform[LOD.Length]; for (int i = 0; i < LOD.Length; ++i) { GameObject lodGo = new GameObject("lod" + i); lodGo.transform.parent = transform; lodParent[i] = lodGo.transform; } MTQuadTreeHeader header = MTFileUtils.LoadQuadTreeHeader(DataName); foreach (var m in header.Meshes.Values) { Mesh[] lods = new Mesh[LOD.Length]; MTFileUtils.LoadMesh(lods, DataName, m.MeshID); for (int i = 0; i < LOD.Length; ++i) { MeshFilter meshF; MeshRenderer meshR; GameObject meshGo = new GameObject("meshObj"); meshGo.transform.parent = lodParent[i]; meshF = meshGo.AddComponent <MeshFilter>(); meshR = meshGo.AddComponent <MeshRenderer>(); meshR.materials = header.RuntimeMats; meshF.sharedMesh = lods[i]; } } } catch { MTLog.LogError("failed to load datas"); } }
private void Awake() { if (DataName == "") { return; } try { mHeader = MTFileUtils.LoadQuadTreeHeader(DataName); mRoot = new MTQuadTreeNode(mHeader.QuadTreeDepth, mHeader.BoundMin, mHeader.BoundMax); foreach (var mh in mHeader.Meshes.Values) { mRoot.AddMesh(mh); } int gridMax = 1 << mHeader.QuadTreeDepth; mVisiblePatches = new MTArray <uint>(gridMax * gridMax); if (lodPolicy.Length < mHeader.LOD) { float[] policy = new float[mHeader.LOD]; for (int i = 0; i < lodPolicy.Length; ++i) { policy[i] = lodPolicy[i]; } lodPolicy = policy; } lodPolicy[0] = Mathf.Clamp(lodPolicy[0], 0.5f * mRoot.Bound.size.x / gridMax, lodPolicy[0]); lodPolicy[lodPolicy.Length - 1] = float.MaxValue; } catch { mHeader = null; mRoot = null; MTLog.LogError("MTLoader load quadtree header failed"); } mCamera = GetComponent <Camera>(); }
// private void OnGUI() { Terrain curentTarget = EditorGUILayout.ObjectField("Convert Target", terrainTarget, typeof(Terrain), true) as Terrain; if (curentTarget != terrainTarget) { ClearAll(); terrainTarget = curentTarget; } int curSliceCount = Mathf.FloorToInt(Mathf.Pow(2, QuadTreeDepth)); int sliceCount = EditorGUILayout.IntField("Slice Count(NxN)", curSliceCount); if (sliceCount != curSliceCount) { curSliceCount = Mathf.NextPowerOfTwo(sliceCount); QuadTreeDepth = Mathf.FloorToInt(Mathf.Log(curSliceCount, 2)); } int lodCount = EditorGUILayout.IntField("LOD Count", LODSettings.Length); if (lodCount != LODSettings.Length) { MTLODSetting[] old = LODSettings; LODSettings = new MTLODSetting[lodCount]; for (int i = 0; i < Mathf.Min(lodCount, old.Length); ++i) { LODSettings[i] = old[i]; } for (int i = Mathf.Min(lodCount, old.Length); i < Mathf.Max(lodCount, old.Length); ++i) { LODSettings[i] = new MTLODSetting(); } } if (LODSettings.Length > 0) { for (int i = 0; i < LODSettings.Length; ++i) { LODSettings[i].OnGUIDraw(i); } } BakeMaterial = EditorGUILayout.ToggleLeft("Bake Material", BakeMaterial); if (BakeMaterial) { BakeTexRes = EditorGUILayout.IntField("Bake Texture Resolution", BakeTexRes); BakeTexRes = Mathf.Min(2048, Mathf.NextPowerOfTwo(BakeTexRes)); } if (GUILayout.Button("Generate")) { if (LODSettings == null || LODSettings.Length == 0) { MTLog.LogError("no lod setting"); return; } if (terrainTarget == null) { MTLog.LogError("no target terrain"); return; } string[] lodFolder = new string[LODSettings.Length]; for (int i = 0; i < LODSettings.Length; ++i) { string guid = AssetDatabase.CreateFolder("Assets", string.Format("{0}_LOD{1}", terrainTarget.name, i)); lodFolder[i] = AssetDatabase.GUIDToAssetPath(guid); } int gridMax = 1 << QuadTreeDepth; dataCreateJob = new CreateDataJob(terrainTarget.terrainData.bounds, gridMax, gridMax, LODSettings); for (int i = 0; i < int.MaxValue; ++i) { dataCreateJob.Update(); EditorUtility.DisplayProgressBar("creating data", "scaning volumn", dataCreateJob.progress); if (dataCreateJob.IsDone) { break; } } dataCreateJob.EndProcess(); tessellationJob = new TessellationJob(dataCreateJob.LODs); for (int i = 0; i < int.MaxValue; ++i) { tessellationJob.Update(); EditorUtility.DisplayProgressBar("creating data", "tessellation", tessellationJob.progress); if (tessellationJob.IsDone) { break; } } for (int i = 0; i < tessellationJob.mesh.Length; ++i) { EditorUtility.DisplayProgressBar("saving data", "processing", (float)i / tessellationJob.mesh.Length); MTMeshData data = tessellationJob.mesh[i]; for (int lod = 0; lod < data.lods.Length; ++lod) { SaveMesh(lodFolder[lod], data.meshId, data.lods[lod], sliceCount); if (!BakeMaterial) { MTMatUtils.SaveMaterials(lodFolder[lod], terrainTarget.name, terrainTarget); } } } if (BakeMaterial) { string guid = AssetDatabase.CreateFolder("Assets", string.Format("{0}_BakedMats", terrainTarget.name)); AssetDatabase.Refresh(); RunBakeMaterial(AssetDatabase.GUIDToAssetPath(guid), terrainTarget, BakeTexRes); } EditorUtility.ClearProgressBar(); AssetDatabase.Refresh(); } }
private void EditorGrabDetails(string folderName, Terrain terrainTarget, int layer) { if (terrainTarget == null) { MTLog.LogError("no active terrain"); return; } TerrainData data = terrainTarget.terrainData; int detailLayerCnt = data.detailPrototypes.Length; int dataLen = data.detailResolution * data.detailResolution; string[] savedAssets = new string[detailLayerCnt]; Bounds bound = data.bounds; float pixelSize = bound.size.x / data.detailResolution; for (int i = 0; i < detailLayerCnt; ++i) { MemoryStream ms = new MemoryStream(); int totalCnt = 0; MTFileUtils.WriteInt(ms, totalCnt); DetailPrototype proto = data.detailPrototypes[i]; //prototype info //raw data int[,] dlayer = data.GetDetailLayer(0, 0, data.detailResolution, data.detailResolution, i); for (int u = 0; u < data.detailResolution; ++u) { for (int v = 0; v < data.detailResolution; ++v) { ushort pixelDen = (ushort)dlayer[v, u]; //gen data inside if (pixelDen <= 0) { continue; } //data count long countOffset = ms.Position; MTFileUtils.WriteUShort(ms, pixelDen); int subGridSize = Mathf.CeilToInt(Mathf.Sqrt(pixelDen)); float start_x = bound.min.x + u * pixelSize; float start_z = bound.min.z + v * pixelSize; ushort spawnedCount = SpawnOnePixel(proto, layer, start_x, start_z, pixelSize, subGridSize, pixelDen, bound.max.y, ms); if (countOffset != pixelDen) { long posCache = ms.Position; ms.Position = countOffset; MTFileUtils.WriteUShort(ms, spawnedCount); ms.Position = posCache; } totalCnt += spawnedCount; EditorUtility.DisplayProgressBar("bake details", "processing", (float)(u * data.detailResolution + v) / (data.detailResolution * data.detailResolution)); } } ms.Position = 0; MTFileUtils.WriteInt(ms, totalCnt); savedAssets[i] = ExportDensity2Bytes(folderName, i, ms); ms.Close(); } EditorUtility.ClearProgressBar(); AssetDatabase.Refresh(); //add componet and parameter GameObject prefabObj = new GameObject("detail_layers"); prefabObj.transform.position = terrainTarget.transform.position; MTDetailBatchRenderer dr = prefabObj.AddComponent <MTDetailBatchRenderer>(); dr.layers = new MTDetailBatchRenderer.ProtoLayerInfo[detailLayerCnt]; for (int i = 0; i < detailLayerCnt; ++i) { DetailPrototype proto = data.detailPrototypes[i]; if (savedAssets[i] == null || proto.prototype == null) { continue; } MeshFilter mf = proto.prototype.GetComponent <MeshFilter>(); if (mf == null) { continue; } MeshRenderer mr = proto.prototype.GetComponent <MeshRenderer>(); if (mr == null) { continue; } TextAsset asset = AssetDatabase.LoadAssetAtPath <TextAsset>(savedAssets[i]); dr.layers[i] = new MTDetailBatchRenderer.ProtoLayerInfo(); dr.layers[i].detailData = asset; dr.layers[i].mesh = mf.sharedMesh; dr.layers[i].mat = mr.sharedMaterial; } dr.bnds = bound; //dr.detailShader = AssetDatabase.LoadAssetAtPath<ComputeShader>("Assets/MightyTerrainMesh/Shaders/TerrainDetailMask"); dr.detailDistance = Terrain.activeTerrain.detailObjectDistance; dr.detailDensity = Terrain.activeTerrain.detailObjectDensity; dr.detailResolution = data.detailResolution; dr.detailResolutionPerPatch = data.detailResolutionPerPatch; string prefabPath = Path.Combine(folderName, "detail_layers.prefab"); PrefabUtility.SaveAsPrefabAsset(prefabObj, prefabPath); DestroyImmediate(prefabObj); AssetDatabase.Refresh(); }