在上一篇中,批量操作的对象是资产Asset,批量的操作主要基于文件的名称和路径实现。而这次工作的对象是场景中的GameObject,批量选取的逻辑主要用到了两个:父子层级关系和Selection选取项。
层级关系与Transform类
Unity场景中的物体主要都是通过树形的父子关系结构来组织的,子物体会严格地随着父物体起移动、旋转、缩放,Transform就记录了这些位置信息,且子物体的变换坐标是在父物体的本地坐标系下的。
因为Unity中每一个GameObject都有且只有一个变换组件(Transform),我们可以通过这些Transform组件来确定go(GameObject,后文略)。
一般组织场景时,同一类物体会放到一个空物体下,以方便管理;lod的子物体也会组织在一个含有LOD Group的空物体下。
我们可以发现,其实GameObject
自身是不存储树形结构的,而[Transform组件][2]
其实才是树形父子结构的载体,所有相关物体层级的方法也都挂载在Transform
组件之下。
例如,对于GameObject _gameObject
来说,它的父物体是:
GameObject _parent = _gameObject.transform.parent.gameObject;
不考虑层级遍历它的所有子物体可以:
Tranform[] subtfs = _gameObject.GetComponentsInChildren<Transform>();
foreach (var subtf in subtfs){
GameObject go = subtf.gameObject;
...
}
遍历它所在下一层的子物体可以:
for(int i = 0; i < _gameObject.transform.childCount; i++){
GameObject go = _gameObject.transform.GetChild(i).gameObject;
...
}
Get Component
Transform组件可以找到所有的子物体,但在这次的工具中,我们只对含有Mesh Render
的物体进行属性更改,这样的需求可以用到这样一系列方法:
T = GetComponent<T>()
T[] = GetComponents<T>()
T = GetComponentInChildren<T>()
T[] = GetComponentsInChildren<T>()
T = GetComponentInParent<T>()
T[] = GetComponentsInParent<T>()
T为组件类型,如果没有则会返回null。
当我们只需要对含某组件的go做操作时,这个方法会更简洁好用:
if(go.TryGetComponent(out T t)){
...
}
(写文章查api的时候才发现,Component也是有上述这些方法的。之前一直以为只有GameObject有,还要先找到go再去获取其他component,就有点大费周章啦)
LOD Group
插件的需求之一是可以根据LOD的不同层级赋不同的属性。他们之间的索引关系如下图所示: 从上到下找是很容易的,这次的实现如下:
//当遇到有lod group的物体时,对子物体进行操作
if (go.TryGetComponent(out LODGroup lg))
{
var lods = lg.GetLODs();
for (int i = 0; i < lg.lodCount; i++)
{
if (lodFilter[i > 3 ? 3 : i])
{
foreach (var renderer in lods[i].renderers)
{
applyGIchanges(renderer as MeshRenderer);
}
}
}
}
Selection选取项
进行批处理时,一个重要的需求是处理选中项,这就需要使用到Selection
类。
[Selection][4]
是UnityEditor中的一个类,管理编辑器中的选取状态。物体的选取有两种状态:Selected
和Active
;在Editor中,高亮标蓝则表明物体处于Selected,而在Properties面板显示的物体的那一个物体则是Active。
在对Scene中物体进行处理时,最常用的就是通过Selection.transforms获取选取的顶级菜单。
扩展一下下,Selection的这些Properties也是可写入的。Hierarchy中,在面板里选择物体并同步到Scene只需要:
// Selection
protected override void SelectionChanged (IList<int> selectedIds)
{
Selection.instanceIDs = selectedIds.ToArray();
}
(之前没有transform的意识的时候都写得Selection.gameObjects....多此一举)