多余的MeshCollider和Animation

 如果你是在做手游项目,我强烈建立不要做碰撞,有关一切物理的东西unity对手机支持的并不好,如果不信你可以试试效率你就知道。美术兄弟,每次给过来的场景,都会带上MeshCollider 和Animation 空的组件。这俩东西很占效率的,不信你可以用Profiler 看看。如果你让美工们上传场景的时候手动检查一下,把MeshCollider和Animation空的组件都删掉,我可以很负责的告诉你,他们肯定会忘删除或者错删。。。比如下图这样的组件。

<ignore_js_op> 

          还有场景的材质最好用Mobile/Diffuse,他会比Diffuse的shader效率高很多,因为它会减少每个点的一次乘法。但是有时候美术需要做贴图的变色, 那就不能用Mobile/Diffuse了。但是后来我看了一下有很多材质用的是Diffuse,但是颜色那里是纯白色,那么shader在渲染的时候每个点都多余的进行了一次乘法的运算(效率白白的浪费了)。。。

           作为程序我们首先要避免策划和美术犯错,果断的写一个插件吧,美术在上传场景之前让运行一下插件,把没用的组件删除掉。

[AppleScript] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
  [MenuItem("Tools/删除场景没用的MeshCollider和Animation")]
  static public void Remove()
  {
    //获取当前场景里的所有游戏对象
          GameObject []rootObjects = (GameObject[])UnityEngine.Object.FindObjectsOfType(typeof(GameObject));
          //遍历游戏对象
          foreach(GameObject go in rootObjects)
          {
            //如果发现Render的shader是Diffuse并且颜色是白色,那么将它的shader修改成Mobile/Diffuse
                  if(go != null && go.transform.parent != null)
                  {
                                  Renderer render = go.GetComponent();
                            if( render != null &&render.sharedMaterial != null && render.sharedMaterial.shader.name == "Diffuse" && render.sharedMaterial.color == Color.white)
                                  {
                                    render.sharedMaterial.shader = Shader.Find("Mobile/Diffuse");
                                  }
                  }
 
//删除所有的MeshCollider
                  foreach(MeshCollider collider in UnityEngine.Object.FindObjectsOfType(typeof(MeshCollider)))
                  {
                          DestroyImmediate(collider);
                  }
 
                  //删除没有用的动画组件
                  foreach(Animation animation in UnityEngine.Object.FindObjectsOfType(typeof(Animation)))
                  {
                          if(animation.clip == null)
                                  DestroyImmediate(animation);
                  }
 
//应该没有人用Animator吧? 避免美术弄错我都全部删除了。
                  foreach(Animator animator in UnityEngine.Object.FindObjectsOfType(typeof(Animator)))
                  {
                                  DestroyImmediate(animator);
                  }
          }
          //保存
          AssetDatabase.SaveAssets();
  }

       如果你的项目中美术已经上传了很多场景,并且你也不知道那个场景有问题,那就快写一个批量删除所有场景的插件吧。
结合上面的代码

[AppleScript] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
[MenuItem("Tools/批量删除所有场景中的MeshCollider 和Animation")]
static public void RemoveAll()
{
        //遍历所有场景
        foreach (UnityEditor.EditorBuildSettingsScene scene in UnityEditor.EditorBuildSettings.scenes)
        {
          //当场景启动中
                if (scene.enabled)
                {
                 //打开这个场景
                        EditorApplication.OpenScene(scene.path);
                        //删除该场景中的所有MeshCollider 和Animation
                        Remove();
                }
        }
        //保存
        EditorApplication.SaveScene();
}

       另外清注意 只有你的场景在BuildSettings页面中注册过UnityEditor.EditorBuildSettings.scenes才能获取场景。如果你的场景没有加到BuildSetting中。 如果想批量添加你可以参考我之前写的文章我还是copy过来吧。

[AppleScript] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
using UnityEngine;
using System.Collections;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
public class Easy : Editor {
 
        [MenuItem("Tools/同步所有场景到SceneSetting文件")]
        static void CheckSceneSetting()
        {
                List dirs = new List();
                GetDirs(Application.dataPath,ref dirs);
                EditorBuildSettingsScene[] newSettings = new EditorBuildSettingsScene[dirs.Count];
                for(int i =0; i< newSettings.Length;i++)
                {
                        newSettings = new EditorBuildSettingsScene(dirs,true);
                }
                EditorBuildSettings.scenes = newSettings;
                EditorApplication.SaveAssets();
        }
        private static void GetDirs(string dirPath, ref List dirs)
        {
                foreach (string path in Directory.GetFiles(dirPath))
                {
                        if(System.IO.Path.GetExtension(path) == ".unity")
                        {
                                dirs.Add(path.Substring(path.IndexOf("Assets/")));
                        }
                }
                if (Directory.GetDirectories(dirPath).Length > 0)
                {
                        foreach (string path in Directory.GetDirectories(dirPath))
                                GetDirs(path,ref dirs);
                }
        }
}

       合并drallCall 最简单的办法就是让美术上传模型的时候勾选一下Static,这样Unity会自动帮我们合并DrawCall.我建议你还是不要相信美术了。帮他们做工具吧。。


       或者你也可以在游戏运行中动态的添加,找一个合适的位置写入如下代码。他会把该游戏对象以及所有子对象全部合并DrawCall。

[AppleScript] 纯文本查看 复制代码
1
StaticBatchingUtility.Combine(gameObject);


这样合并DrawCall的很方便,而且也很简单。但是无法修改所有子对象的坐标、旋转、缩放了,但是可以修改父对象。如下图所示,比如我给a 设置了static属性,或者 Combine(a.gameObject) ,那么如果代码中你需要操作b 或者 c 的Transform那么是不行的, 但是你可以操作a。 他会带着 b 和c 一起Transform。



嘿嘿,美术处理这些东西真是。“美工靠得住,母猪会上树” 嘿嘿嘿嘿。 不过不要紧,亲爱的美术,我们程序会想办法帮你们检查错误的, 嘿嘿嘿嘿。

posted @ 2014-09-13 21:28  Harlan1009  阅读(460)  评论(0编辑  收藏  举报