工具向TANotes

🔍TOOL丨批处理2.0:Lighting工具[1] - 批处理逻辑

by ERIN.Z, 2022-06-22


在上一篇中,批量操作的对象是资产Asset,批量的操作主要基于文件的名称和路径实现。而这次工作的对象是场景中的GameObject,批量选取的逻辑主要用到了两个:父子层级关系和Selection选取项。

层级关系与Transform类

Unity场景中的物体主要都是通过树形的父子关系结构来组织的,子物体会严格地随着父物体起移动、旋转、缩放,Transform就记录了这些位置信息,且子物体的变换坐标是在父物体的本地坐标系下的。

因为Unity中每一个GameObject都有且只有一个变换组件(Transform),我们可以通过这些Transform组件来确定go(GameObject,后文略)。

在我们的场景中,物体的结构大体是这样的: Transform

一般组织场景时,同一类物体会放到一个空物体下,以方便管理;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 从上到下找是很容易的,这次的实现如下:

//当遇到有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中的一个类,管理编辑器中的选取状态。物体的选取有两种状态:SelectedActive;在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....多此一举)

by ERIN.Z

2024 © typecho & elise