如果你是在做手游项目,我强烈建立不要做碰撞,有关一切物理的东西Unity对手机支持的并不好,如果不信你可以试试效率你就知道。美术兄弟,每次给过来的场景,都会带上MeshCollider 和Animation 空的组件。这俩东西很占效率的,不信你可以用Profiler 看看。如果你让美工们上传场景的时候手动检查一下,把MeshCollider和Animation空的组件都删掉,我可以很负责的告诉你,他们肯定会忘删除或者错删。。。比如下图这样的组件。
还有场景的材质最好用Mobile/Diffuse,他会比Diffuse的shader效率高很多,因为它会减少每个点的一次乘法。但是有时候美术需要做贴图的变色, 那就不能用Mobile/Diffuse了。但是后来我看了一下有很多材质用的是Diffuse,但是颜色那里是纯白色,那么shader在渲染的时候每个点都多余的进行了一次乘法的运算(效率白白的浪费了)。。。
作为程序我们首先要避免策划和美术犯错,果断的写一个插件吧,美术在上传场景之前让运行一下插件,把没用的组件删除掉。
1 2 3 4 5 6 7 8 9 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 41 42 |
[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<Renderer>(); 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(); } |
如果你的项目中美术已经上传了很多场景,并且你也不知道那个场景有问题,那就快写一个批量删除所有场景的插件吧。
结合上面的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
[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过来吧。
1 2 3 4 5 6 7 8 9 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 |
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<string> dirs = new List<string>(); GetDirs(Application.dataPath,ref dirs); EditorBuildSettingsScene[] newSettings = new EditorBuildSettingsScene[dirs.Count]; for(int i =0; i< newSettings.Length;i++) { newSettings[i] = new EditorBuildSettingsScene(dirs[i],true); } EditorBuildSettings.scenes = newSettings; EditorApplication.SaveAssets(); } private static void GetDirs(string dirPath, ref List<string> 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。
1 2 3 |
StaticBatchingUtility.Combine(gameObject); |
这样合并DrawCall的很方便,而且也很简单。但是无法修改所有子对象的坐标、旋转、缩放了,但是可以修改父对象。如下图所示,比如我给a 设置了static属性,或者 Combine(a.gameObject) ,那么如果代码中你需要操作b 或者 c 的Transform那么是不行的, 但是你可以操作a。 他会带着 b 和c 一起Transform。
嘿嘿,美术处理这些东西真是。“美工靠得住,母猪会上树” 嘿嘿嘿嘿。 不过不要紧,亲爱的美术,我们程序会想办法帮你们检查错误的, 嘿嘿嘿嘿。
- 本文固定链接: https://www.xuanyusong.com/archives/2564
- 转载请注明: 雨松MOMO 于 雨松MOMO程序研究院 发表
你好!雨松大大,是这样的,我是一名学生,我现在遇到一个问题,一个物体上有两个collider,一个是触发器一个是碰撞器,触发器包这碰撞器,我的射线ray 穿不透触发器,这是为什么?我砍了官方的一个例子,噩梦射手,他的射线可以穿透触发器,我新建了一个项目,简化了他的代码,发现还是没办法穿透触发器,这是项目本身要设置什么的缘故吗?
你可以用 Physics.RaycastAll 方法来发送射线, 这个可以穿透所有碰到的射线的collider
谢谢雨松老师,我已经找到原因了,原因是我的Edit->Project Setting->Physics 里的Queries Hit Trigger 是勾选的,改为缺选之后,射线就可以穿过触发器了。
hi,雨松,我执行第一段代码的时候报Assets/Editor/RemoveComponent.cs(14,42): error CS0103: The name `rootObjects’ does not exist in the current context这是什么原因呢
大神我在用第一个脚本的时候报错~Assets/Tools/Remove.cs(2,28): error CS0116: A namespace can only contain types and namespace declarations怎么解决啊,我是美术看不懂哎。
那检测碰撞一般都用什么啊?
你好,上文中“合并drallCall 最简单的办法就是让美术上传模型的时候勾选一下Static”,是直接在Unity中设置成noting就可以是吧?
是把Static前面的√勾上
我顺便把missing的脚本也剔除了。。好多特效都有missing脚本
嗯。
不做mesh碰撞?那可以做box碰撞吗?,或者应该怎么做地图碰撞?
手游不要做碰撞?包括触发么?不做碰撞的话,需要碰撞的东西怎么办呢
学习了,一般都是自己手动删除的,脚本操作很方便,谢谢啦。
如果不用 MeshCollider, 用BoxCollider 效果会好很多吗?
请教下,老动画支持IK功能吗?还有指定身体的部位动画遮盖如何实现?
momo,我想问下,为啥你会说没有用animator,这个新的动画系统mecanim不是挺好的?
mecanim 我不太喜欢用, 我比较喜欢纯代码, 这样比较灵活。。
谢谢。