static void HLODApply(bool stream, LODVolume node) { s_LODVolume.Clear(); s_LODVolume.Enqueue(node); while (s_LODVolume.Count > 0) { LODVolume lodVolume = s_LODVolume.Dequeue(); foreach (var child in lodVolume.childVolumes) { if (child.combined == null && child.childVolumes.Count < 1) { continue; } s_LODVolume.Enqueue(child); } if (lodVolume.combined != null) { if (stream) { if (!lodVolume.combined.CheckState()) { ChoiceQueue(lodVolume, lodVolume.combined); } continue; } lodVolume.combined.ApplyEnable(); } } }
static void SetHLODEnable(LODVolume node, bool bEnable) { if (node.combined != null) { SetLOGGroupEnable(node.combined, bEnable); } }
public static LODVolume Create(HLODGenerate hlodGenerate) { int volumeCount = hlodGenerate.m_LODVolumeCount++; GameObject go = new GameObject(k_DefaultName + volumeCount, typeof(LODVolume)); LODVolume volume = go.GetComponent <LODVolume>(); volume.m_CurrHLODGenerate = hlodGenerate ? hlodGenerate : volume.m_CurrHLODGenerate; return(volume); }
static void SetLODEnable(LODVolume node, bool bEnable) { if (node.combined == null) { // 由于有一种情况是单个模型时,不会合并 // 所以这里如果没有合并的模型,就看看有没有单独的模型需要设置 foreach (var lodGroup in node.lodGroups) { SetLOGGroupEnable(lodGroup, bEnable); } } }
//检查是否为所在树的贴图集 bool CheckInCurrLittleOctree(LODVolume lodVolume, TextureAtlasData rootData) { LODVolume[] parents = lodVolume.GetComponentsInParent <LODVolume>(); foreach (LODVolume p in parents) { if (p.gameObject == rootData.m_Root)//找到我是该大贴图的孩子 { return(true); } } return(false); }
//选择卸载或加载队列 static void ChoiceQueue(LODVolume node, UnityLODGroupFast fast) { if (node.childTreeRoot == null) { node.childTreeRoot = node.gameObject.AddComponent <ChildTreeRoot>(); } if (fast.EnabledVirtual) { node.childTreeRoot.AddLoadAsset(fast); } else { node.childTreeRoot.AddUnLoadAsset(fast); } }
/*生成SceneLOD接口,指定hlodGenerate*/ public void GenerateSceneLODByHLODGenerate(HLODGenerate hlodGenerate, Action <GameObject, GameObject> endCall = null) { m_CurrHLODGenerate = hlodGenerate; #if UNITY_EDITOR if (hlodGenerate.m_RootLODVolume) { m_RootVolume = hlodGenerate.m_RootLODVolume.GetComponent <LODVolume>(); } else { m_RootVolume = null; } m_CreateRootVolumeForScene = SceneManager.GetActiveScene().name; MonoBehaviourHelper.StartCoroutine(GenerateHLOD(hlodGenerate.m_Targets, endCall)); #endif }
IEnumerator SetRootLODVolume() { if (m_RootVolume) { var rootVolumeTransform = m_RootVolume.transform; var transformRoot = rootVolumeTransform.root; if (transformRoot.GetComponent <HLODGenerate>())//已经是根节点 { yield break; } // Handle the case where the BVH has grown if (rootVolumeTransform != transformRoot) { m_RootVolume = transformRoot.GetComponent <LODVolume>(); } yield break; } // Handle initialization or the case where the BVH has shrunk LODVolume lodVolume = null; var scene = SceneManager.GetActiveScene(); var rootGameObjects = scene.GetRootGameObjects(); foreach (var go in rootGameObjects) { if (!go) { continue; } lodVolume = go.GetComponent <LODVolume>(); if (lodVolume) { break; } yield return(null); } if (lodVolume) { m_RootVolume = lodVolume; } }
/*是否重新生成*/ bool IsReGenerate(LODVolume lodVolume, Texture2D[] textures, TextureAtlas atlas) { //父节点有使用不删除 Transform currParent = lodVolume.transform.parent; LODVolume parentVolume = currParent.GetComponent <LODVolume>(); //自己是root,贴图数量不一样更新 //父节点没有合并,说明自己是子树的父节点,从自己开始 if (parentVolume == null || parentVolume.combined == null) { IEnumerable <Texture2D> residueOld = atlas.textures.Except(textures); IEnumerable <Texture2D> residueNew = textures.Except(atlas.textures); return(residueOld.Any() | residueNew.Any()); } return(false); }
//还原HLOD public static void ComeBackHLODAsset(this HLODGenerate hlodGenerate, HLODGenerateEditor editor) { #if UNITY_EDITOR if (hlodGenerate.m_RootLODVolume == null) { return; } #endif Queue <LODVolume> queue = new Queue <LODVolume>(); #if UNITY_EDITOR queue.Enqueue(hlodGenerate.m_RootLODVolume.GetComponent <LODVolume>()); #endif while (queue.Count > 0) { LODVolume lodVolume = queue.Dequeue(); foreach (var child in lodVolume.childVolumes) { queue.Enqueue(child); } if (lodVolume.combined == null) { continue; } GameObject obj = AssetDatabase.LoadAssetAtPath <GameObject>(lodVolume.combined._assetPath); if (obj) { #if UNITY_EDITOR obj = PrefabUtility.InstantiatePrefab(obj, hlodGenerate.m_HLODS.transform) as GameObject; #endif obj.transform.SetPositionAndRotation(lodVolume.combined.Pose.position, lodVolume.combined.Pose.rotation); obj.transform.localScale = lodVolume.combined.Pose.scale; obj.GetComponent <MeshRenderer>().enabled = false; lodVolume.combined._hlodRoot = obj; lodVolume.combined._lodGroup = obj.GetComponent <LODGroup>(); if (editor.m_DeleteStreamingAsset) { PrefabUtility.UnpackPrefabInstance(obj, PrefabUnpackMode.OutermostRoot, InteractionMode.AutomatedAction); } } } }
void SetChildDirty(LODVolume lv) { Queue <LODVolume> queue = new Queue <LODVolume>(); queue.Enqueue(lv); while (queue.Count > 0) { LODVolume lodVolume = queue.Dequeue(); foreach (LODVolume l in lodVolume.childVolumes) { if (l.lodGroups.Count <= 1) { continue; } l.dirty = true; EditorUtility.DisplayProgressBar("设置需要更改的节点", l.name, 0.8f); queue.Enqueue(l); } } }
//还远原始资源 public static void ComeBackOriginalAsset(this HLODGenerate hlodGenerate) { #if UNITY_EDITOR LODVolume root = hlodGenerate.m_RootLODVolume.GetComponent <LODVolume>(); foreach (var lodGroup in root.lodGroups) { GameObject obj = AssetDatabase.LoadAssetAtPath <GameObject>(lodGroup._assetPath); if (obj) { obj = PrefabUtility.InstantiatePrefab(obj, hlodGenerate.m_HLODS.transform) as GameObject; obj.transform.parent = lodGroup._hlodRoot.transform;//生成流式资源后_hlodRoot引用的是父节点 obj.transform.SetPositionAndRotation(lodGroup.Pose.position, lodGroup.Pose.rotation); obj.transform.localScale = lodGroup.Pose.scale; lodGroup._hlodRoot = obj; lodGroup._lodGroup = obj.GetComponent <LODGroup>(); lodGroup.Enabled = true; } } #endif }
/*生成prefab*/ void GeneratePrefab(LODVolume lodVolume, string savePath) { if (lodVolume.combined._hlodRoot == null) { return; } string namePath = null; if (PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(lodVolume.combined._hlodRoot) == "") { lodVolume.combined._hlodRoot.GetComponent <MeshRenderer>().enabled = true; namePath = Path.Combine(savePath, lodVolume.combined._hlodRoot.name + ".prefab"); PrefabUtility.SaveAsPrefabAsset(lodVolume.combined._hlodRoot, namePath); lodVolume.combined._assetPath = namePath.Replace("\\", "/"); } DestroyImmediate(lodVolume.combined._hlodRoot); lodVolume.combined._hlodRoot = null; lodVolume.combined._lodGroup = null; }
IEnumerator ShrinkByLodGroup() { var populatedChildrenNodes = 0; foreach (Transform child in transform) { var lodVolume = child.GetComponent <LODVolume>(); if (lodGroups != null && lodGroups.Count > 0 && lodGroups.Count(r => r != null) > 0) { populatedChildrenNodes++; } yield return(null); } if (populatedChildrenNodes <= 1) { var lodVolumes = GetComponentsInChildren <LODVolume>(); LODVolume newRootVolume = null; if (lodVolumes.Length > 0) { newRootVolume = lodVolumes[lodVolumes.Length - 1]; newRootVolume.transform.parent = null; } // Clean up child HLODs before destroying the GameObject; Otherwise, we'd leak into the scene foreach (var lodVolume in lodVolumes) { if (lodVolume != newRootVolume) { lodVolume.CleanupHLOD(); } } DestroyImmediate(gameObject); if (newRootVolume) { yield return(newRootVolume.ShrinkByLodGroup()); } } }
/*将精细用资源地址引用,并删除,把自己的位置存放父节点,以便还原使用*/ void GenrateFineModelRef(LODVolume rootLODVolume) { foreach (var fast in rootLODVolume.lodGroups) { if (fast._hlodRoot == null) { continue; } string path = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(fast._hlodRoot); if (path == "") { Debug.LogError("找不到预制体!!"); continue; } Transform parent = fast._hlodRoot.transform.parent; DestroyImmediate(fast._hlodRoot); fast._assetPath = path.Replace("\\", "/"); fast._hlodRoot = parent ? parent.gameObject : null; fast._lodGroup = null; fast.Enabled = false; } }
/*更新流式资源*/ void UpdataStreamingAsset(HLODGenerate hlodGenerate) { string savePath = Path.Combine(hlodGenerate.m_StreamingAssetPath, s_StreamingDirectory); if (!Directory.Exists(savePath)) { Directory.CreateDirectory(savePath); } LODVolume rootLODVolume = hlodGenerate.m_RootLODVolume.GetComponent <LODVolume>(); Queue <LODVolume> queue = new Queue <LODVolume>(); queue.Enqueue(rootLODVolume); AssetDatabase.StartAssetEditing(); while (queue.Count > 0) { LODVolume lodVolume = queue.Dequeue(); foreach (var child in lodVolume.childVolumes) { queue.Enqueue(child); } if (lodVolume.combined == null) { continue; } //导出资源 GeneratePrefab(lodVolume, savePath); } AssetDatabase.StopAssetEditing(); GenrateFineModelRef(hlodGenerate.m_RootLODVolume.GetComponent <LODVolume>()); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); }
/*更新合批网格*/ void UpdataCombineMesh(HLODGenerate hlodGenerate) { if (!hlodGenerate.m_IsExportMesh) { return; } if (hlodGenerate.m_MeshAssetPath == "") { EditorUtility.DisplayDialog("警告", "没有选择mesh路径,请先选择路径", "是"); hlodGenerate.m_IsExportMesh = false; return; } Queue <LODVolume> queue = new Queue <LODVolume>(); queue.Enqueue(hlodGenerate.m_RootLODVolume.GetComponent <LODVolume>()); //AssetDatabase.StartAssetEditing(); while (queue.Count > 0) { LODVolume lodVolume = queue.Dequeue(); if (lodVolume.combined != null && lodVolume.combined._hlodRoot != null) { string path = AssetDatabase.GetAssetPath(lodVolume.combined._hlodRoot.GetComponent <MeshFilter>().sharedMesh); if (lodVolume.lodGroups.Count < 1)//删除多出来的资源 { if (path == "") { path = Path.Combine(hlodGenerate.m_MeshAssetPath, ExportHLODsByMesh.s_DirectoryName, lodVolume.combined._hlodRoot.name); path = Path.ChangeExtension(path, "asset"); } DestroyImmediate(lodVolume.GetComponent <LODGroup>()); DestroyImmediate(lodVolume.combined._hlodRoot); lodVolume.combined._hlodRoot = null; if (path != "") { AssetDatabase.DeleteAsset(path); } } else if (path == "")//更新资源 { //ExportHLODsByMesh.PersistHLODs(lodVolume.hlodRoot.transform, hlodGenerate.m_MeshAssetPath); ExportHLODsByMesh.PersistHLODOfFbx(lodVolume.combined._hlodRoot.transform, hlodGenerate.m_MeshAssetPath); if (!hlodGenerate.StreamUpdate.Contains(lodVolume)) { hlodGenerate.StreamUpdate.Add(lodVolume); } } EditorUtility.SetDirty(lodVolume); } foreach (LODVolume lv in lodVolume.childVolumes) { queue.Enqueue(lv); } } //AssetDatabase.StopAssetEditing(); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); }
static void OnCameraPreCull(Camera camera) { if (!Application.isPlaying) { return; } if (camera.cameraType != CameraType.Game || camera.tag != "MainCamera") { return; } // 刷新间隔没到,不做任何处理 if (CullData.m_lastCullTime + s_CullInterval > Time.realtimeSinceStartup && s_delayEnable) { return; } CullData.m_lastCullTime = Time.realtimeSinceStartup; //判断摄像机参数是否有变化 var cameraTransform = camera.transform; var cameraPosition = cameraTransform.position; var cameraRotation = cameraTransform.rotation; if (CullData.m_LastCameraPosition != cameraPosition) { CullData.m_LastCameraPosition = cameraPosition; m_SceneDirty = true; } /* * if (CullData.m_LastCameraRotation != cameraRotation) * { * CullData.m_LastCameraRotation = cameraRotation; * m_SceneDirty = true; * } */ if (CullData.m_LastFOV != camera.fieldOfView) { CullData.m_LastFOV = camera.fieldOfView; m_SceneDirty = true; } //判断LOD精度设置是否有变化 if (CullData.m_LastLODBias != UnityEngine.QualitySettings.lodBias) { CullData.m_LastLODBias = UnityEngine.QualitySettings.lodBias; m_SceneDirty = true; } if (CullData.m_LastHLODBias != s_HLOD_Bias) { CullData.m_LastHLODBias = s_HLOD_Bias; m_SceneDirty = true; } if (m_SceneDirty) { foreach (var tree in Alls) { //判断是否超过距离缓冲,超过了再改变状态 if (Vector3.Distance(tree.m_LastCameraPosition, cameraPosition) < tree.s_CacheDistance) { continue; } tree.m_LastCameraPosition = cameraPosition; LODVolume rootLODVolume = tree.m_RootVolume; if (rootLODVolume == null) { continue; } tree.HLODPreCull(camera, camera.transform.position); HLODApply(tree.m_Stream, rootLODVolume); foreach (var lodGroup in rootLODVolume.lodGroups) { if (tree.m_Stream) { if (!lodGroup.CheckState()) { ChoiceQueue(lodGroup._lodVolume, lodGroup); } continue; } lodGroup.ApplyEnable(); } } CullData.m_LastCameraPosition = cameraPosition; CullData.m_LastCameraRotation = cameraRotation; m_SceneDirty = false; } }
//TODO 准备将这一步移植到Job System void HLODPreCull(Camera camera, Vector3 cameraPos) { s_AuxStack.Clear(); List <LODVolume> backSort = m_BackSort; if (!s_HLODEnabled)//不开HLOD { foreach (var lv in backSort) { if (lv.combined) { SetLOGGroupEnable(lv.combined, false); } } foreach (var lodGroup in m_RootVolume.lodGroups) { SetLOGGroupEnable(lodGroup, true); } return; } for (int index = 0; index < backSort.Count - 1; index++) { LODVolume curLv = backSort[index]; LODVolume nextLv = backSort[index + 1]; s_AuxStack.Push(curLv); if (curLv.deep <= nextLv.deep) { //表示后续遍历还没遍历到当前节点的父节点,继续入栈 continue; } bool parentVisible = true; //下降,表示遍历到了父节点,把栈顶前面几个相同的兄弟节点处理,然后将当前节点入栈 while (s_AuxStack.Count > 0) { LODVolume node = s_AuxStack.Pop(); if (node.combined == null && node.childVolumes.Count > 0) { //遇到没有合并的父节点 continue; } bool allChildInvisible = false; if (node.childVolumes.Count == 0) { foreach (var lodGroup in node.lodGroups) { if (lodGroup.GetCurrentLOD(camera, cameraPos) != lodGroup.lodCount - 1) { // 只要有一个显示最精细模型 // 就认为不能显示HLOD对象 allChildInvisible = true; parentVisible = false; break; } } // 修改所有原始模型的显示状态 foreach (var lodGroup in node.lodGroups) { SetLOGGroupEnable(lodGroup, allChildInvisible); } //设置合批模型状态 if (node.combined) { SetLOGGroupEnable(node.combined, !allChildInvisible); } } else if (parentVisible != false) //不是叶子节点,且兄弟节点没有显示 { if (node.combined.EnabledVirtual) //如果当前节点显示就不管,否则自己显示了,那么父节点需要隐藏 { continue; } parentVisible = false; } LODVolume who = null; if (s_AuxStack.Count > 0) { who = s_AuxStack.Peek(); } else { break; } //下一个是上层节点 if (who.deep != node.deep) { break; } } if (nextLv.combined != null) { s_AuxStack.Push(nextLv); if (parentVisible) { //孩子合批都显示,所以隐藏孩子显示自己 foreach (var child in nextLv.childVolumes) { SetHLODEnable(child, false); } } else { //父节点不能显示,激活叶子没有合并的LODGroup foreach (var child in nextLv.childVolumes) { SetLODEnable(child, true); } } SetLOGGroupEnable(nextLv.combined, parentVisible); } } }
public IEnumerator GetTextureAtlas(HLODGenerate hg, LODVolume lodVolume, Texture2D[] textures, Texture2D[] normals, Action <TextureAtlasData> callback) { TextureAtlasData atlasData = null; List <TextureAtlasData> atlasesData = null; GetTextureAtlasList(hg, out atlasesData); yield return(null); foreach (var a in atlasesData) { if (a.m_State == TextureAtlasData.State.Delete) { continue; } //检查是否为所在树的贴图集 if (!CheckInCurrLittleOctree(lodVolume, a)) { continue; } //是否重新生成 if (IsReGenerate(lodVolume, textures, a.m_Atlases)) { a.m_State = TextureAtlasData.State.Delete; break; } // At a minimum the atlas should have all of the textures requested, but can be a superset if (!textures.Except(a.m_Atlases.textures).Any()) { atlasData = a; break; } yield return(null); } //m_Atlases.Remove(deleteAtlas); if (atlasData == null)//没有找到图集就创建一个 { atlasData = new TextureAtlasData(null, TextureAtlasData.State.Add); atlasData.m_Material = new Material(Shader.Find("Standard")); /*先序遍历,所有根节点就是第一个创建的对象,子节点会找到这个图集而不会继续创建*/ atlasData.m_Root = lodVolume.gameObject; } if (!atlasData.m_Atlases) { atlasData.m_Atlases = ScriptableObject.CreateInstance <TextureAtlas>(); TextureReadableSetting(textures); //TextureReadableSetting(normals); CombineTexture(textures, atlasData.m_Atlases, false, callback); //CombineTexture(normals, atlasData.m_Atlases, true, callback); atlasData.m_Material.mainTexture = atlasData.m_Atlases.textureAtlas; //material.SetTexture("_NormalMap", atlasData.m_Atlases.textureAtlas_N); atlasesData.Add(atlasData); yield return(null); } if (callback != null) { callback(atlasData); } }
/*更新BVH后一些检查操作*/ public IEnumerator CheckAfterBVHUpdata(int treeHeight) { Queue <LODVolume> queue = new Queue <LODVolume>(); //将没用合批的父节点dirty设置成false queue.Enqueue(this); while (queue.Count > 0) { LODVolume lodVolume = queue.Dequeue(); int deep = lodVolume.ChildDeep(); if (lodVolume.combined != null || deep <= treeHeight) { continue; } lodVolume.dirty = false; foreach (LODVolume lv in lodVolume.childVolumes) { queue.Enqueue(lv); } EditorUtility.DisplayProgressBar("剔除不必要更改的节点", lodVolume.name, 0.3f); } yield return(null); /*剔除空引用,广度遍历*/ queue.Clear(); queue = new Queue <LODVolume>(); queue.Enqueue(this); while (queue.Count > 0) { LODVolume lodVolume = queue.Dequeue(); lodVolume.lodGroups.RemoveAll(r => {//有物体删除了 if (r == null) { if (lodVolume.combined != null) { lodVolume.deleteDirty = true; } return(true); } return(false); }); if (lodVolume.deleteDirty || lodVolume.dirty) { EditorUtility.DisplayProgressBar("设置需要更改的节点", lodVolume.name, 0.5f); lodVolume.dirty = true; SetChildDirty(lodVolume); } if (lodVolume.lodGroups.Count <= 1 && !lodVolume.deleteDirty) { lodVolume.dirty = false; continue; } lodVolume.deleteDirty = false; foreach (LODVolume lv in lodVolume.childVolumes) { queue.Enqueue(lv); } } }
IEnumerator UpdateOctreeByLodGroup(GameObject[] gameObjects = null) { if (gameObjects == null || gameObjects.Count() < 1) { yield break; } if (!m_RootVolume) { if (m_CreateRootVolumeForScene == SceneManager.GetActiveScene().name) { #if UNITY_EDITOR m_RootVolume = LODVolume.Create(m_CurrHLODGenerate); #endif } else { yield break; } } var lodGroups = m_FoundLODGroups; lodGroups.Clear(); foreach (var objRoot in gameObjects) { LODGroup [] childGroups = objRoot.GetComponentsInChildren <LODGroup>(); lodGroups.AddRange(childGroups); } // Remove any renderers that should not be there (e.g. HLODs) lodGroups.RemoveAll(r => m_ExcludedLODGroups.Contains(r) ); lodGroups.RemoveAll(l => { if (l) { // Check against previous collection if (m_ExcludedLODGroups.Contains(l)) { return(false); } var rds = l.GetLODs()[0].renderers; foreach (var r in rds) { if (r == null) { return(false); } var mf = r.GetComponent <MeshFilter>(); if (!mf || (mf.sharedMesh && mf.sharedMesh.GetTopology(0) != MeshTopology.Triangles)) { m_ExcludedLODGroups.Add(l); return(true); } #if UNITY_EDITOR //根据包围盒直径进行剔除不需要计算的模型 if (m_CurrHLODGenerate.m_BVHDivide.m_Cull) { bool result = m_CurrHLODGenerate.m_BVHDivide.CullByMesh(r.transform); if (result) { m_ExcludedLODGroups.Add(l); return(true); } } #endif } } return(false); }); var existingLODGroups = m_ExistingLODGroups; existingLODGroups.Clear(); existingLODGroups.UnionWith(m_RootVolume.lodGroups.Select(l => l._lodGroup)); var removed = m_RemovedLODGroups; removed.Clear(); removed.UnionWith(m_ExistingLODGroups); removed.ExceptWith(lodGroups); var added = m_AddedLODGroups; added.Clear(); added.UnionWith(lodGroups); added.ExceptWith(existingLODGroups); int count = 1; foreach (var l in removed) { if (existingLODGroups.Contains(l)) { #if UNITY_EDITOR yield return(m_RootVolume.RemoveLodGroup(l)); #endif // Check if the BVH shrunk yield return(SetRootLODVolume()); } } count = 1; foreach (var l in added) { EditorUtility.DisplayProgressBar("网格划分", l.name, (float)count++ / added.Count); if (!existingLODGroups.Contains(l)) { UnityLODGroupFast lodGroupFast = CreateInstance <UnityLODGroupFast>(); #if UNITY_EDITOR lodGroupFast.Init(l, l.gameObject); //UnityLODGroupFast lodGroupFast = new UnityLODGroupFast(l, l.gameObject); yield return(m_RootVolume.AddLodGroup(lodGroupFast)); #endif l.transform.hasChanged = false; // Check if the BVH grew yield return(SetRootLODVolume()); } } }
public IEnumerator Batch(HLODGenerate hg, LODVolume lodVolume) { GameObject go = lodVolume.combined._hlodRoot; var renderers = go.GetComponentsInChildren <Renderer>(); var materials = new HashSet <Material>(renderers.SelectMany(r => r.sharedMaterials)); List <Texture2D> textures = new List <Texture2D>(); List <Texture2D> normals = new List <Texture2D>(); textures = new HashSet <Texture2D>(materials.Select(m => { if (m) { return(m.mainTexture as Texture2D); } return(null); }).Where(t => t != null)).ToList(); textures.Add(whiteTexture); /* * foreach(var t2d in textures) * { * foreach(var rd in renderers) * { * if(rd.sharedMaterial.mainTexture == t2d) * { * Texture2D t = rd.sharedMaterial.GetTexture("_BumpMap") as Texture2D; * if (t == null) * { * var texture = new Texture2D(rd.sharedMaterial.mainTexture.width, rd.sharedMaterial.mainTexture.height, TextureFormat.RGB24, false, PlayerSettings.colorSpace == ColorSpace.Linear); * * t = texture; * //texture.Apply(); * } * else if(t.width != rd.sharedMaterial.mainTexture.width || t.height != rd.sharedMaterial.mainTexture.height) * { * int width = rd.sharedMaterial.mainTexture.width; * int height = rd.sharedMaterial.mainTexture.height; * var texture = new Texture2D(rd.sharedMaterial.mainTexture.width, rd.sharedMaterial.mainTexture.height, t.format, false, PlayerSettings.colorSpace == ColorSpace.Linear); * * * for(int i = 0; i < height; i++) * { * for(int j = 0; j <width; j++) * { * //EditorUtility.DisplayProgressBar("fsdfasd", (height * width).ToString(), (float)(i * j) / (height * width)); * // Color newColor = t.GetPixelBilinear(j / width, i / height); * texture.SetPixel(j, i, Color.white); * } * } * //EditorUtility.ClearProgressBar(); * texture.Apply(); * t = texture; * } * normals.Add(t); * break; * } * } * } * normals.Add(whiteTexture); */ TextureAtlasData atlasData = null; yield return(TextureAtlasModule.instance.GetTextureAtlas(hg, lodVolume, textures.ToArray(), normals.ToArray(), a => atlasData = a)); var mainAtlasLookup = new Dictionary <Texture2D, Rect>(); //var normalAtlasLookup = new Dictionary<Texture2D, Rect>(); var atlasTextures = atlasData.m_Atlases.textures; for (int i = 0; i < atlasTextures.Length; i++) { mainAtlasLookup[atlasTextures[i]] = atlasData.m_Atlases.uvs[i]; } MeshFilter[] meshFilters = go.GetComponentsInChildren <MeshFilter>(); var combine = new List <CombineInstance>(); for (int i = 0; i < meshFilters.Length; i++) { var mf = meshFilters[i]; var sharedMesh = mf.sharedMesh; if (!sharedMesh) { continue; } if (!sharedMesh.isReadable) { var assetPath = AssetDatabase.GetAssetPath(sharedMesh); if (!string.IsNullOrEmpty(assetPath)) { var importer = AssetImporter.GetAtPath(assetPath) as ModelImporter; if (importer) { importer.isReadable = true; importer.SaveAndReimport(); } } } var ci = new CombineInstance(); var mesh = UnityEngine.Object.Instantiate(sharedMesh); var mr = mf.GetComponent <MeshRenderer>(); var sharedMaterials = mr.sharedMaterials; var uv = mesh.uv; if (uv == null) { uv = mesh.uv2; } var colors = mesh.colors; if (colors == null || colors.Length == 0) { colors = new Color[uv.Length]; } var updated = new bool[uv.Length]; var triangles = new List <int>(); // Some meshes have submeshes that either aren't expected to render or are missing a material, so go ahead and skip var subMeshCount = Mathf.Min(mesh.subMeshCount, sharedMaterials.Length); for (int j = 0; j < subMeshCount; j++) { var sharedMaterial = sharedMaterials[Mathf.Min(j, sharedMaterials.Length - 1)]; var mainTexture = whiteTexture; var materialColor = Color.white; if (sharedMaterial) { var texture = sharedMaterial.mainTexture as Texture2D; //sharedMaterial.texture if (texture) { mainTexture = texture; } if (sharedMaterial.HasProperty("_Color")) { materialColor = sharedMaterial.color; } } if (mesh.GetTopology(j) != MeshTopology.Triangles) { Debug.LogWarning("Mesh must have triangles", mf); continue; } triangles.Clear(); mesh.GetTriangles(triangles, j); var uvOffset = mainAtlasLookup[mainTexture]; foreach (var t in triangles) { if (!updated[t]) { var uvCoord = uv[t]; if (mainTexture == whiteTexture) { // Sample at center of white texture to avoid sampling edge colors incorrectly uvCoord.x = 0.5f; uvCoord.y = 0.5f; } while (uvCoord.x < 0) { uvCoord.x += 1; } while (uvCoord.y < 0) { uvCoord.y += 1; } while (uvCoord.x > 1) { uvCoord.x -= 1; } while (uvCoord.y > 1) { uvCoord.y -= 1; } uvCoord.x = Mathf.Lerp(uvOffset.xMin, uvOffset.xMax, uvCoord.x); uvCoord.y = Mathf.Lerp(uvOffset.yMin, uvOffset.yMax, uvCoord.y); uv[t] = uvCoord; if (mainTexture == whiteTexture) { colors[t] = materialColor; } else { colors[t] = Color.white; } updated[t] = true; } } yield return(null); } mesh.uv = uv; mesh.uv2 = null; mesh.colors = colors; ci.mesh = mesh; ci.transform = mf.transform.localToWorldMatrix; combine.Add(ci); mf.gameObject.SetActive(false); yield return(null); } var combinedMesh = new Mesh(); #if UNITY_2017_3_OR_NEWER combinedMesh.indexFormat = IndexFormat.UInt32; #endif combinedMesh.CombineMeshes(combine.ToArray(), true, true); combinedMesh.RecalculateBounds(); var meshFilter = go.AddComponent <MeshFilter>(); meshFilter.sharedMesh = combinedMesh; for (int i = 0; i < meshFilters.Length; i++) { UnityEngine.Object.DestroyImmediate(meshFilters[i].gameObject); } var meshRenderer = go.AddComponent <MeshRenderer>(); meshRenderer.sharedMaterial = atlasData.m_Material; atlasData.m_MeshRenderers.Add(meshRenderer); }
/*更新BVH,对生成的BVH做后处理,广度遍历*/ public IEnumerator UpdateRootVolume(Action <List <LODVolume> > action) { Queue <LODVolume> queue = new Queue <LODVolume>(); //给每个子树添加ChildTreeRoot queue.Enqueue(this); while (queue.Count > 0) { LODVolume lodVolume = queue.Dequeue(); if (lodVolume.combined != null) { ChildTreeRoot treeRoot = lodVolume.gameObject.AddComponent <ChildTreeRoot>(); continue; } foreach (LODVolume lv in lodVolume.childVolumes) { queue.Enqueue(lv); } EditorUtility.DisplayProgressBar("添加ChildTreeRoot", lodVolume.name, 0.3f); } //叶子节点,给每个UnityLODGroup做引用,同时所有子树的节点引用ChildTreeRoot queue.Enqueue(this); while (queue.Count > 0) { LODVolume lodVolume = queue.Dequeue(); foreach (LODVolume lv in lodVolume.childVolumes) { queue.Enqueue(lv); } if (lodVolume.childVolumes.Count < 1) { foreach (var fast in lodVolume.lodGroups) { fast._lodVolume = lodVolume; } } lodVolume.childTreeRoot = lodVolume.GetComponentInParent <ChildTreeRoot>(); EditorUtility.DisplayProgressBar("引用ChildTreeRoot", lodVolume.name, 0.6f); } //设置节点深度 int curLevelNum = 0; //当前层的节点数 int curLevel = 1; //层数 queue.Enqueue(this); while (queue.Count > 0) { curLevelNum = queue.Count; while (curLevelNum-- > 0) { LODVolume lodVolume = queue.Dequeue(); lodVolume.deep = curLevel; foreach (LODVolume lv in lodVolume.childVolumes) { queue.Enqueue(lv); } EditorUtility.DisplayProgressBar("深度设置", lodVolume.name, 0.8f); } curLevel++; } //构造后续遍历列表 List <LODVolume> backSort = new List <LODVolume>(); Stack <LODVolume> stack = new Stack <LODVolume>(); stack.Push(this); while (stack.Count > 0) { LODVolume lodVolume = stack.Pop(); backSort.Add(lodVolume); foreach (LODVolume lv in lodVolume.childVolumes) { stack.Push(lv); } EditorUtility.DisplayProgressBar("构造后续遍历列表", lodVolume.name, 0.9f); } backSort.Reverse(); if (action != null) { action.Invoke(backSort); } yield return(null); }