模型的 LOD 比較簡單,直接使用 Unity 提供的組件 LODGroup 掛到模型物體上,然后分別指定不同 LOD 級別的 Renderer 即可。
LODGroup 並不是用距離來控制 LOD,而是用物體在屏幕上的顯示范圍的高度與屏幕高度的比值來決定物體使用哪一級 LOD。這相當於用物體在屏幕上的面積大小來決定 LOD,避免了不同大小的物體在相同距離上使用相同的 LOD 這一不合理的情況。
如果要提供允許玩家指定物體精細度顯示范圍的設置,則需要動態修改這個比值。
Unity 沒有對粒子系統提供 LOD 功能。如果要對粒子系統做 LOD,我認為可以通過控制粒子的最大數量來實現 LOD,並且參照距離來決定使用哪一級 LOD(因為要計算粒子系統的包圍盒,並不是一件容易的事,需要算上所有存活粒子的位置,反而增加運算量)。
粒子特效質量,可以簡單的分 3 個質量級別:低中高,以供玩家在設置中選擇。每個質量級別在各自定義的一段距離內使用各自定義的一個縮放系數,超出此距離的則線性衰減此系數。使用此系數縮小粒子的最大數量。
1 // 3 個質量級別下各自最高 LOD 級別的距離百分比(粒子能以此 LOD 級別顯示的距離百分比) 2 3 float[] HIGH_LEVEL_DISTANCE_PERCENTS = { xxx, xxx, xxx }
1 // 3 個質量級別下各自最高 LOD 級別的粒子數量縮放系數 2 3 float[] HIGH_LEVEL_SCALES = { 0.25, 0.5, 1}
提供一個函數,它可以返回在指定效果質量下指定距離處的縮放系數:
1 float getParticleCountScale(int level, float distPercent) // distPercent 是個距離百分比,並不是絕對值 2 { 3 float highLevelDist = HIGH_LEVEL_DISTANCE_PERCENTS[level]; 4 float highLevelScale = HIGH_LEVEL_SCALES[level]; 5 if (distPercent <= highLevelDist) 6 { 7 return highLevelScale; 8 } 9 else 10 { 11 // 超出最高 LOD 距離的,線性衰減 12 float factor = (1 - distPercent) / (1 - highLevelDist); 13 float scale = highLevelScale * factor; 14 return scale; 15 } 16 }
將這個縮放系數與粒子在預制件中的原始最大數量相乘,得出的新的最大數量再設回給粒子系統即可。
然而美術在預制件里設的粒子的最大數量並不准確,很多時候會設一個粒子在生命周期內不可能達到的特別大的數字,目的只是為了他做效果可以有足夠的施展空間。這就需要我們程序自己估算一下粒子的最大數量了。
我估算粒子最大數量的方法是:最大數量 = 生命周期 x 發射速度
Unity 的粒子系統,很多參數(比如這里要用的生命周期和發射速度)都可能是個曲線,這時挑選幾個采樣點,采樣后取平均值吧,畢竟只是估算而已。
有了最大數量(別忘了乘上縮放系數),設回給粒子系統時會發現,maxParticles 其實是個只讀屬性,沒關系,使用反射機制可以修改此值。
1 // ps 是個 UnityEngine.ParticleSystem 對象 2 System.Type mainType = ps.main.GetType(); 3 System.Reflection.PropertyInfo pi = mainType.GetProperty("maxParticles"); 4 // newMaxCount 是我們計算出來的新的最大數量 5 pi.SetValue(ps.main, newMaxCount, null);