Unity性能优化之特效合并

特效合并,意思是说将粒子所用的零碎图片,以shader为单位合并成一张图集,好处就是可以降低draw call。试想,合并前每个粒子使用一个material,而每一个material就要占用一个drawcall,而合并后多个粒子可以用同一个material,这样就降低了drawcall,提升了性能。

转载请注明出处:http://www.cnblogs.com/jietian331/p/8625078.html

合并工具的代码如下:

1 1 using System; 2 2 using System.Collections.Generic; 3 3 using System.IO; 4 4 using System.Linq; 5 5 using System.Text; 6 6 using UnityEditor; 7 7 using UnityEngine; 8 8 9 9 namespace AssetBundle 10 10 { 11 11 public class ParticleSystemCombiner : ScriptableObject 12 12 { 13 13 public const string 14 14 AtlasFolder = "Assets/Cloth/Resources/ParticleSystemAtlas", 15 15 ParticleAtlasPath = "Assets/Cloth/Resources/ParticleSystemAtlas/particle_atlas.prefab", 16 16 SettingFilepath = "Assets/Editor/ParticleSystemCombinerSetting.csv"; 17 17 18 18 static string[] EffectObjFolders = new string[] 19 19 { 20 20 "Assets/Cloth/Resources/Effect/Cloth", 21 21 "Assets/Cloth/Resources/Model/Equip", 22 22 }; 23 23 24 24 static ParticleAtlases s_atlasesData; 25 25 static List<string> s_materials; 26 26 static Dictionary<string, int> s_texturesSize; 27 27 28 28 static ParticleAtlases AtlasesData 29 29 { 30 30 get 31 31 { 32 32 if (s_atlasesData == null) 33 33 s_atlasesData = AssetDatabase.LoadAssetAtPath<ParticleAtlases>(ParticleAtlasPath); 34 34 return s_atlasesData; 35 35 } 36 36 } 37 37 38 38 static Dictionary<string, int> TexturesSize 39 39 { 40 40 get 41 41 { 42 42 if (s_texturesSize == null) 43 43 { 44 44 s_texturesSize = new Dictionary<string, int>(); 45 45 46 46 string[] lines = File.ReadAllLines(SettingFilepath); 47 47 bool decode = false; 48 48 foreach (var line in lines) 49 49 { 50 50 if (!decode) 51 51 { 52 52 if (line.StartsWith("# Texture Size")) 53 53 { 54 54 decode = true; 55 55 } 56 56 } 57 57 else 58 58 { 59 59 if (line.StartsWith("#")) 60 60 { 61 61 decode = false; 62 62 } 63 63 } 64 64 65 65 if (decode) 66 66 { 67 67 string[] words = line.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); 68 68 if (words.Length > 1) 69 69 { 70 70 string name = words[0]; 71 71 int size; 72 72 int.TryParse(words[1], out size); 73 73 if (size != 0) 74 74 s_texturesSize[name] = size; 75 75 } 76 76 } 77 77 } 78 78 } 79 79 return s_texturesSize; 80 80 } 81 81 } 82 82 83 83 84 84 static List<string> NotCombineTextures 85 85 { 86 86 get 87 87 { 88 88 List<string> list = new List<string>(); 89 89 string[] lines = File.ReadAllLines(SettingFilepath); 90 90 bool decode = false; 91 91 foreach (var line in lines) 92 92 { 93 93 if (!decode) 94 94 { 95 95 if (line.StartsWith("# Not Combine Textures")) 96 96 { 97 97 decode = true; 98 98 } 99 99 } 100100 else 101101 { 102102 if (line.StartsWith("#")) 103103 { 104104 decode = false; 105105 } 106106 } 107107 108108 if (decode) 109109 { 110110 string[] words = line.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); 111111 if (words.Length > 0 && !string.IsNullOrEmpty(words[0])) 112112 { 113113 list.Add(words[0]); 114114 } 115115 } 116116 } 117117 return list; 118118 } 119119 } 120120 121121 #region for build 122122 123123 public static void ClearCache() 124124 { 125125 s_atlasesData = null; 126126 s_materials = null; 127127 } 128128 129129 public static List<ParticleAtlases.TextureItem> GetParticlesUsedAtlas(GameObject effectObj) 130130 { 131131 List<ParticleAtlases.TextureItem> texturesData = new List<ParticleAtlases.TextureItem>(); 132132 ParticleSystem[] particles = effectObj.GetComponentsInChildren<ParticleSystem>(true); 133133 134134 foreach (ParticleSystem ps in particles) 135135 { 136136 ParticleSystemRenderer render = ps.GetComponent<ParticleSystemRenderer>(); 137137 if (!render || !render.sharedMaterial) 138138 { 139139 Debug.LogWarning("Particle no material: " + ps.name); 140140 continue; 141141 } 142142 143143 Texture texture = render.sharedMaterial.mainTexture; 144144 if (ps.textureSheetAnimation.enabled || !texture) 145145 continue; 146146 147147 foreach (var atlasData in AtlasesData.Atlases) 148148 { 149149 foreach (var t in atlasData.Textures) 150150 { 151151 if (t.Name == texture.name) 152152 { 153153 texturesData.Add(t); 154154 break; 155155 } 156156 } 157157 } 158158 } 159159 160160 return texturesData; 161161 } 162162 163163 public static void ProcessEffectObj(GameObject obj) 164164 { 165165 ParticleSystem[] particles = obj.GetComponentsInChildren<ParticleSystem>(true); 166166 167167 foreach (ParticleSystem ps in particles) 168168 { 169169 ParticleSystemRenderer render = ps.GetComponent<ParticleSystemRenderer>(); 170170 if (!render || !render.sharedMaterial) 171171 { 172172 Debug.LogWarning("Particle no material: " + ps.name); 173173 continue; 174174 } 175175 176176 Texture texture = render.sharedMaterial.mainTexture; 177177 if (ps.textureSheetAnimation.enabled || !texture) 178178 continue; 179179 180180 ParticleAtlases.Atlas target = AtlasesData.Atlases.FirstOrDefault(a => a.Textures.Any(t => t.Name == texture.name && t.ShaderName == render.sharedMaterial.shader.name)); 181181 182182 if (target != null) 183183 { 184184 ParticleLoader loader = ps.GetComponent<ParticleLoader>(); 185185 if (!loader) 186186 loader = ps.gameObject.AddComponent<ParticleLoader>(); 187187 loader.TextureName = texture.name; 188188 loader.ShaderName = render.sharedMaterial.shader.name; 189189 render.sharedMaterial = null; 190190 191191 if (!ps.trails.enabled) 192192 render.trailMaterial = null; 193193 } 194194 } 195195 196196 EditorUtility.SetDirty(obj); 197197 AssetDatabase.SaveAssets(); 198198 } 199199 200200 public static List<string> GetAllMaterials() 201201 { 202202 if (s_materials != null) 203203 return s_materials; 204204 205205 List<string> effects; 206206 Dictionary<Shader, List<ParticleSystem>> dic = GetAllParticles(out effects); 207207 s_materials = new List<string>(); 208208 209209 foreach (var pair in dic) 210210 { 211211 foreach (ParticleSystem ps in pair.Value) 212212 { 213213 ParticleSystemRenderer r = ps.GetComponent<ParticleSystemRenderer>(); 214214 string path = AssetDatabase.GetAssetPath(r.sharedMaterial); 215215 if (!s_materials.Contains(path)) 216216 s_materials.Add(path); 217217 } 218218 } 219219 220220 return s_materials; 221221 } 222222 223223 #endregion 224224 225225 226226 [MenuItem("BuildTool/AssetBundle/Combine Particle System")] 227227 static void Init() 228228 { 229229 CombineAllEffectTextures(); 230230 231231 EditorUtility.DisplayDialog("finished", "All work finished.", "ok"); 232232 } 233233 234234 static Dictionary<Shader, List<ParticleSystem>> GetAllParticles(out List<string> effectObjs) 235235 { 236236 // 获取所有的粒子 237237 List<ParticleSystem> particlesList = new List<ParticleSystem>(); 238238 List<string> objPaths = new List<string>(); 239239 foreach (var effectObjFolder in EffectObjFolders) 240240 { 241241 string[] paths = Directory.GetFiles(effectObjFolder, "*.prefab", SearchOption.AllDirectories); 242242 objPaths.AddRange(paths); 243243 } 244244 effectObjs = new List<string>(); 245245 246246 foreach (string path in objPaths) 247247 { 248248 string pathFixed = path.Replace("\\", "/"); 249249 effectObjs.Add(pathFixed); 250250 GameObject obj = AssetDatabase.LoadAssetAtPath<GameObject>(pathFixed); 251251 ParticleSystem[] particles = obj.GetComponentsInChildren<ParticleSystem>(true); 252252 253253 foreach (ParticleSystem ps in particles) 254254 { 255255 ParticleSystemRenderer r = ps.GetComponent<ParticleSystemRenderer>(); 256256 bool needCombine = !ps.textureSheetAnimation.enabled 257257 && r.sharedMaterial 258258 && r.sharedMaterial.shader.name != "Particles/Alpha Blended Premultiply" 259259 && r.sharedMaterial.mainTexture 260260 && r.sharedMaterial.mainTexture.width == r.sharedMaterial.mainTexture.height; 261261 if (needCombine) 262262 particlesList.Add(ps); 263263 } 264264 } 265265 266266 // 分类 267267 Dictionary<Shader, List<ParticleSystem>> dic = new Dictionary<Shader, List<ParticleSystem>>(); 268268 foreach (ParticleSystem ps in particlesList) 269269 { 270270 ParticleSystemRenderer r = ps.GetComponent<ParticleSystemRenderer>(); 271271 var shader = r.sharedMaterial.shader; 272272 if (!dic.ContainsKey(shader)) 273273 dic[shader] = new List<ParticleSystem>(); 274274 dic[shader].Add(ps); 275275 } 276276 277277 return dic; 278278 } 279279 280280 public static List<string> CombineAllEffectTextures() 281281 { 282282 List<string> atlases = new List<string>(); 283283 284284 // 获取所有的粒子 285285 List<string> effects; 286286 Dictionary<Shader, List<ParticleSystem>> dic = GetAllParticles(out effects); 287287 288288 // combine 289289 Dictionary<Texture2D, Material> dictTextures = new Dictionary<Texture2D, Material>(); 290290 List<ParticleAtlases.Atlas> atlasesData = new List<ParticleAtlases.Atlas>(); 291291 List<string> notCombineTextures = NotCombineTextures; 292292 293293 foreach (var pair in dic) 294294 { 295295 // get textures 296296 dictTextures.Clear(); 297297 foreach (ParticleSystem ps in pair.Value) 298298 { 299299 ParticleSystemRenderer r = ps.GetComponent<ParticleSystemRenderer>(); 300300 Texture2D texture = (Texture2D)r.sharedMaterial.mainTexture; 301301 if (!notCombineTextures.Contains(texture.name) && !dictTextures.ContainsKey(texture)) 302302 dictTextures.Add(texture, r.sharedMaterial); 303303 } 304304 305305 if (dictTextures.Count < 2) 306306 continue; 307307 308308 Texture2D[] texturesArray = dictTextures.Keys.ToArray(); 309309 310310 // combine texture 311311 string atlasName = string.Format("ParticleAtlas_{0}", Path.GetFileNameWithoutExtension(pair.Key.name)); 312312 string atlasPath = string.Format("{0}/{1}.png", AtlasFolder, atlasName); 313313 Uploader.CreateDirectory(atlasPath); 314314 Rect[] rects; 315315 Vector2[] textureSizes; 316316 Texture2D atlas = CombineTextures(texturesArray, atlasPath, out rects, out textureSizes); 317317 atlases.Add(atlasPath); 318318 319319 // create material 320320 string matPath = string.Format("{0}/{1}.mat", AtlasFolder, atlasName); 321321 Material mat = AssetDatabase.LoadAssetAtPath<Material>(matPath); 322322 if (mat == null) 323323 { 324324 mat = new Material(pair.Key); 325325 AssetDatabase.CreateAsset(mat, matPath); 326326 } 327327 mat.mainTexture = atlas; 328328 329329 // get config 330330 ParticleAtlases.TextureItem[] texturesData = new ParticleAtlases.TextureItem[texturesArray.Length]; 331331 for (int i = 0; i < texturesArray.Length; i++) 332332 { 333333 Rect rect = rects[i]; 334334 Texture2D texture2D = texturesArray[i]; 335335 Vector2 textureSize = textureSizes[i]; // will resize temp texture, so cann't use texture2D.width 336336 int numTilesX = (int)(atlas.width / textureSize.x); 337337 int numTilesY = (int)(atlas.height / textureSize.y); 338338 int colIndex = (int)(rect.x * numTilesX); 339339 int rowIndex = (int)(numTilesY - 1 - rect.y * numTilesY); 340340 int index = rowIndex * numTilesX + colIndex; 341341 342342 // get color 343343 Material oldMat = dictTextures[texture2D]; 344344 Color32 oldColor = oldMat.GetColor("_TintColor"); 345345 string strColor = string.Format("{0}_{1}_{2}_{3}", oldColor.r, oldColor.g, oldColor.b, oldColor.a); 346346 347347 string shaderName = oldMat.shader.name; 348348 349349 int depth = oldMat.renderQueue; 350350 351351 texturesData[i] = new ParticleAtlases.TextureItem() 352352 { 353353 Color = oldColor, 354354 Depth = depth, 355355 Index = index, 356356 Name = texture2D.name, 357357 NumTilesX = numTilesX, 358358 NumTilesY = numTilesY, 359359 ShaderName = shaderName, 360360 }; 361361 } 362362 363363 ParticleAtlases.Atlas atlasData = new ParticleAtlases.Atlas() 364364 { 365365 Material = mat, 366366 Textures = texturesData, 367367 }; 368368 atlasesData.Add(atlasData); 369369 } 370370 371371 GameObject prefabObj = AssetDatabase.LoadAssetAtPath<GameObject>(ParticleAtlasPath); 372372 if (!prefabObj) 373373 prefabObj = PrefabUtility.CreatePrefab(ParticleAtlasPath, new GameObject()); 374374 ParticleAtlases atlasesCom = prefabObj.GetComponent<ParticleAtlases>(); 375375 if (!atlasesCom) 376376 atlasesCom = prefabObj.AddComponent<ParticleAtlases>(); 377377 atlasesCom.Atlases = atlasesData.ToArray(); 378378 prefabObj.name = Path.GetFileNameWithoutExtension(ParticleAtlasPath); 379379 380380 EditorUtility.SetDirty(prefabObj); 381381 AssetDatabase.SaveAssets(); 382382 383383 Debug.Log("All cloth effect textures combine finished!"); 384384 385385 return atlases; 386386 } 387387 388388 static Texture2D CombineTextures(Texture2D[] textures, string path, out Rect[] rects, out Vector2[] textureSizes) 389389 { 390390 if (textures == null || textures.Length < 1) 391391 { 392392 Debug.LogError("None textures"); 393393 rects = null; 394394 textureSizes = null; 395395 return null; 396396 } 397397 398398 string tempFolderName = "_TempImages"; 399399 string tempFolder = "Assets/" + tempFolderName; 400400 AssetDatabase.DeleteAsset(tempFolder); 401401 AssetDatabase.CreateFolder("Assets", tempFolderName); 402402 403403 List<string> newPaths = new List<string>(); 404404 var newTextures = new Texture2D[textures.Length]; 405405 textureSizes = new Vector2[textures.Length]; 406406 407407 // 将原来的图片复制一份出来 408408 for (int i = 0; i < textures.Length; i++) 409409 { 410410 string texPath = AssetDatabase.GetAssetPath(textures[i]); 411411 if (File.Exists(texPath)) 412412 { 413413 string newPath = string.Format("{0}/{1}", tempFolder, Path.GetFileName(texPath)); 414414 AssetDatabase.CopyAsset(texPath, newPath); 415415 newPaths.Add(newPath); 416416 } 417417 else 418418 { 419419 Debug.Log("File not exists: " + texPath); 420420 } 421421 } 422422 423423 // make it readable 424424 for (int i = 0; i < newPaths.Count; i++) 425425 { 426426 string newPath = newPaths[i]; 427427 SetSourceTextureReadalbe(newPath); 428428 Texture2D t = AssetDatabase.LoadAssetAtPath<Texture2D>(newPath); 429429 textureSizes[i] = new Vector2(t.width, t.height); 430430 431431 // 去掉边缘的一个像素 432432 if (t.width > 4) 433433 { 434434 for (int j = 0; j < t.width; j++) 435435 { 436436 t.SetPixel(j, 0, new Color(0, 0, 0, 0)); 437437 t.SetPixel(j, 1, new Color(0, 0, 0, 0)); 438438 t.SetPixel(j, t.height - 1, new Color(0, 0, 0, 0)); 439439 t.SetPixel(j, t.height - 2, new Color(0, 0, 0, 0)); 440440 } 441441 } 442442 443443 if (t.height > 4) 444444 { 445445 for (int z = 0; z < t.height; z++) 446446 { 447447 t.SetPixel(0, z, new Color(0, 0, 0, 0)); 448448 t.SetPixel(1, z, new Color(0, 0, 0, 0)); 449449 t.SetPixel(t.width - 1, z, new Color(0, 0, 0, 0)); 450450 t.SetPixel(t.width - 2, z, new Color(0, 0, 0, 0)); 451451 } 452452 } 453453 454454 newTextures[i] = t; 455455 } 456456 457457 // pack 458458 Texture2D atlas = new Texture2D(1, 1, TextureFormat.ARGB32, false); 459459 rects = atlas.PackTextures(newTextures, 0, 4096, false); 460460 461461 // save 462462 byte[] bytes = atlas.EncodeToPNG(); 463463 File.WriteAllBytes(path, bytes); 464464 AssetDatabase.Refresh(); 465465 AssetDatabase.SaveAssets(); 466466 467467 // setting 468468 TextureCompresser.CompressRGBA(path); 469469 470470 // 删除临时目录 471471 AssetDatabase.DeleteAsset(tempFolder); 472472 473473 AssetDatabase.Refresh(); 474474 AssetDatabase.SaveAssets(); 475475 476476 return AssetDatabase.LoadAssetAtPath<Texture2D>(path); 477477 } 478478 479479 static void SetSourceTextureReadalbe(string path) 480480 { 481481 string name = Path.GetFileNameWithoutExtension(path); 482482 int maxSize; 483483 TexturesSize.TryGetValue(name, out maxSize); 484484 if (maxSize == 0) 485485 maxSize = 64; 486486 487487 bool readable = true; 488488 TextureImporterNPOTScale npotScale = TextureImporterNPOTScale.ToNearest; 489489 TextureWrapMode wrapMode = TextureWrapMode.Clamp; 490490 TextureImporterCompression compression = TextureImporterCompression.Uncompressed; 491491 492492 bool changed = false; 493493 494494 var importer = (TextureImporter)AssetImporter.GetAtPath(path); 495495 TextureImporterSettings settings = new TextureImporterSettings(); 496496 importer.ReadTextureSettings(settings); 497497 498498 settings.alphaIsTransparency = true; 499499 settings.mipmapEnabled = false; 500500 501501 if (settings.readable != readable) 502502 { 503503 settings.readable = readable; 504504 changed = true; 505505 } 506506 507507 if (settings.npotScale != npotScale) 508508 { 509509 settings.npotScale = npotScale; 510510 changed = true; 511511 } 512512 513513 if (settings.wrapMode != wrapMode) 514514 { 515515 settings.wrapMode = wrapMode; 516516 changed = true; 517517 } 518518 519519 if (importer.maxTextureSize != maxSize) 520520 { 521521 importer.maxTextureSize = maxSize; 522522 changed = true; 523523 } 524524 525525 if (importer.textureCompression != compression) 526526 { 527527 importer.textureCompression = compression; 528528 changed = true; 529529 } 530530 531531 // set platform overriten as false 532532 var androidSetting = importer.GetPlatformTextureSettings("Android"); 533533 var iosSetting = importer.GetPlatformTextureSettings("iPhone"); 534534 var pcSetting = importer.GetPlatformTextureSettings("Standalone"); 535535 if (androidSetting.overridden) 536536 { 537537 androidSetting.overridden = false; 538538 changed = true; 539539 } 540540 if (iosSetting.overridden) 541541 { 542542 iosSetting.overridden = false; 543543 changed = true; 544544 } 545545 if (pcSetting.overridden) 546546 { 547547 pcSetting.overridden = false; 548548 changed = true; 549549 } 550550 importer.SetPlatformTextureSettings(androidSetting); 551551 importer.SetPlatformTextureSettings(iosSetting); 552552 importer.SetPlatformTextureSettings(pcSetting); 553553 554554 if (changed) 555555 { 556556 importer.SetTextureSettings(settings); 557557 AssetDatabase.ImportAsset(path); 558558 } 559559 } 560560 561561 } 562562 }

ParticleSystemCombiner

加载的代码:

11 using UnityEngine; 22 33 public partial class ParticleLoader : MonoBehaviour 44 { 55 public string TextureName; 66 public string ShaderName; 77 }

ParticleLoader

1 1 using Common; 2 2 using UnityEngine; 3 3 4 4 public partial class ParticleLoader : MonoBehaviour 5 5 { 6 6 static ParticleAtlases s_atlases; 7 7 8 8 9 9 // 加载图集 10 10 public static void Initialize() 11 11 { 12 12 BundleLoader.Singleton.LoadAssetBundle("atlases/particlesystematlas.u", r => 13 13 { 14 14 GameObject[] objs = r.Bundle.LoadAllAssets<GameObject>(); 15 15 s_atlases = objs[0].GetComponent<ParticleAtlases>(); 16 16 }); 17 17 } 18 18 19 19 void OnEnable() 20 20 { 21 21 Load(); 22 22 } 23 23 24 24 void Load() 25 25 { 26 26 ParticleSystemRenderer renderer = GetComponent<ParticleSystemRenderer>(); 27 27 if (!renderer) 28 28 return; 29 29 30 30 ParticleAtlases.Atlas targetAtlas = null; 31 31 ParticleAtlases.TextureItem targetTextureConfig = null; 32 32 33 33 // 找对应的配置 34 34 for (int i = 0; i < s_atlases.Atlases.Length; i++) 35 35 { 36 36 ParticleAtlases.Atlas atlasData = s_atlases.Atlases[i]; 37 37 for (int j = 0; j < atlasData.Textures.Length; j++) 38 38 { 39 39 ParticleAtlases.TextureItem textureData = atlasData.Textures[j]; 40 40 if (textureData.Name == this.TextureName && textureData.ShaderName == this.ShaderName) 41 41 { 42 42 targetAtlas = atlasData; 43 43 targetTextureConfig = textureData; 44 44 break; 45 45 } 46 46 } 47 47 48 48 if (targetAtlas != null) 49 49 break; 50 50 } 51 51 52 52 if (targetAtlas != null && targetTextureConfig != null) 53 53 { 54 54 ParticleSystem ps = GetComponent<ParticleSystem>(); 55 55 56 56 renderer.sharedMaterial = targetAtlas.Material; // 渲染 57 57 58 58 SetTextureSheet(ps, targetTextureConfig); // 设置格子 59 59 60 60 SetStartColor(ps, renderer, targetTextureConfig.Color); // 设置颜色 61 61 62 62 SetDepth(renderer, targetTextureConfig); // 排序 63 63 } 64 64 } 65 65 66 66 // 设置格子 67 67 void SetTextureSheet(ParticleSystem ps, ParticleAtlases.TextureItem targetTextureConfig) 68 68 { 69 69 var tsa = ps.textureSheetAnimation; 70 70 float curveConstant = (float)targetTextureConfig.Index / targetTextureConfig.NumTilesX / targetTextureConfig.NumTilesY; 71 71 tsa.enabled = true; 72 72 tsa.numTilesX = targetTextureConfig.NumTilesX; 73 73 tsa.numTilesY = targetTextureConfig.NumTilesY; 74 74 tsa.animation = ParticleSystemAnimationType.WholeSheet; 75 75 tsa.startFrame = new ParticleSystem.MinMaxCurve(0); 76 76 tsa.frameOverTime = new ParticleSystem.MinMaxCurve(curveConstant); 77 77 tsa.cycleCount = 1; 78 78 } 79 79 80 80 // 设置颜色 81 81 void SetStartColor(ParticleSystem ps, ParticleSystemRenderer renderer, Color matColor) 82 82 { 83 83 var main = ps.main; 84 84 switch (main.startColor.mode) 85 85 { 86 86 case ParticleSystemGradientMode.Color: 87 87 case ParticleSystemGradientMode.Gradient: 88 88 case ParticleSystemGradientMode.RandomColor: 89 89 case ParticleSystemGradientMode.TwoGradients: 90 90 var targetColor = main.startColor.color * matColor; 91 91 main.startColor = new UnityEngine.ParticleSystem.MinMaxGradient(targetColor); 92 92 break; 93 93 94 94 case ParticleSystemGradientMode.TwoColors: 95 95 var colorMin = main.startColor.colorMin * matColor; 96 96 var colorMax = main.startColor.colorMax * matColor; 97 97 main.startColor = new UnityEngine.ParticleSystem.MinMaxGradient(colorMin, colorMax); 98 98 break; 99 99 100100 default: 101101 Debug.LogError("Unknown mode: " + main.startColor.mode); 102102 break; 103103 } 104104 105105 renderer.sharedMaterial.SetColor("_TintColor", Color.white); 106106 } 107107 108108 // 排序 109109 void SetDepth(ParticleSystemRenderer renderer, ParticleAtlases.TextureItem targetTextureConfig) 110110 { 111111 int depth = targetTextureConfig.Depth; 112112 if (depth > 0 && renderer.sharedMaterial.renderQueue < depth) 113113 renderer.sharedMaterial.renderQueue = depth; 114114 } 115115 116116 }

ParticleLoader

 合并后的图集如下:

 合并后的粒子如下:

效果如下:

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )