0%

Unity编辑器开发练习——图片资源导入配置工具

一、什么是 AssertPostprocessor

官方解释: AssetPostprocessor 允许您挂接到导入管线并在导入资源前后运行脚本。

详情见官方 API 介绍: AssetPostprocessor

如果项目中需要导入的资源较多,资源的属性就需要在 Inspector 面板中一个一个的进行配置,这很麻烦。而 AssetPostprocessor 可以在我们导入资源时,Unity 自动帮我们将资源的属性按照我们在脚本里写的设置配置好。

一些常用的方法如下:

  • OnPreprocessTexture:在导入纹理贴图之前调用
  • OnPreprocessModel:在导入模型之前调用
  • OnPreprocessAudio:在导入音频之前调用

  • OnPostprocessTexture:在导入纹理贴图之后调用

  • OnPostprocessModel:在导入模型之后调用
  • OnPostprocessAudio:在导入音频之后调用
  • OnPostprocessAllAssets:所有资源的导入,删除,移动操作都会调用该方法

二、简单应用实列

1、在 Assets 文件夹下新建一个 Editor 文件夹,

关于 Editor 文件夹:

  • 该文件夹可以放在项目的任何文件夹下,可以有多个”Editor”文件夹。
  • 编辑器扩展相关的脚本都要放在该文件夹内,该文件夹中的脚本只会对 Unity 编辑器起作用。
  • 项目打包的时候,不会被打包到项目中。如果编辑器相关脚本不放在该文件夹中,打包项目可能会出错。
  • 如果非要有些编辑器相关脚本不放在该文件夹中,需要在该类的前后加上 UNITY_EDITOR 的宏定义

关于 Editor Default Resources 文件夹

必须放在 Project 视图的根目录下,可以把编辑器用到的一些资源放在这里。该文件夹和 Editor 文件夹一样都不会被打到最终发布包里,仅仅用于开发时使用。可以直接通过 EditorGUIUtility.Load 去读取该文件夹下的资源。

2、在 Editor 下面新建一个 C#脚本,该脚本必须继承自 AssetPostprocessor

【具体代码】

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
using UnityEngine;
using UnityEditor;
public class MyEditor : AssetPostprocessor {

// Texture导入之前调用,针对Texture进行设置
public void OnPreprocessTexture()
{
Debug.Log ("纹理资源预处理: "+this.assetPath);
TextureImporter impor = this.assetImporter as TextureImporter;
impor.textureType = TextureImporterType.Sprite;
impor.alphaSource = TextureImporterAlphaSource.FromGrayScale;
impor.isReadable = true;
}

// Texture导入之后调用,针对Texture进行设置
// public void OnPostprocessTexture(Texture2D tex)
// {
// Debug.Log ("纹理资源后处理: "+ this.assetPath);
// }

// 所有的资源的导入,删除,移动,都会调用此方法,注意,这个方法是static的
public static void OnPostprocessAllAssets(string[] importedAssets,string[] deletedAssets,string[] movedAssets,string[] movedFromAssetPaths)
{
Debug.Log ("======================资源发生变化=========================");
foreach (string str in importedAssets)
{
Debug.Log("重新导入资源: " + str);
}
foreach (string str in deletedAssets)
{
Debug.Log("删除资源: " + str);
}

for (int i = 0; i < movedAssets.Length; i++)
{
Debug.Log("Moved Asset: " + movedAssets[i] + " from: " + movedFromAssetPaths[i]);
}
}
}

3、将资源拖入项目中,即可实现资源属性的自动配置

【效果】

将图片拖入后,Inspector 面板设置如下

三、打包并使用编辑器

1、创建一个自定义的包

具体细则见官方文档: 创建自定义包

【标准包布局】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<root>
├── package.json
├── README.md
├── CHANGELOG.md
├── LICENSE.md
├── Editor
│ ├── Unity.[YourPackageName].Editor.asmdef
│ └── EditorExample.cs
├── Runtime
│ ├── Unity.[YourPackageName].asmdef
│ └── RuntimeExample.cs
├── Tests
│ ├── Editor
│ │ ├── Unity.[YourPackageName].Editor.Tests.asmdef
│ │ └── EditorExampleTest.cs
│ └── Runtime
│ ├── Unity.[YourPackageName].Tests.asmdef
│ └── RuntimeExampleTest.cs
└── Documentation~
└── [YourPackageName].md

【Package 命名规范】

  • 包名起始必须为 com.,例如 com.unity.timeline
  • 若在 UI 显示则需低于 50 个字符,否则可低于 214 个字符
  • 仅包含小写字母、数字、连字符-、下划线_和点.
  • 为表明命名空间,可在命名空间后缀加点。如 com.unity.2d.animation 和 com.unity.2d.ik

以下是简化版的步骤,并不规范

首先在 项目名/Packages 目录下创建一个文件夹作为自定义的包,在该文件夹下创建一个 Editor 文件夹、一个 Runtime 文件夹、一个 package.json 文件,在 Editor 文件夹下创建 MyTextureImportProcess.cs 、MyPackage.EditorTests.asmdef。

1
2
3
4
5
6
<root>
├── package.json
├── Editor
│ ├── MyPackage.EditorTests.asmdef
│ └── MyTextureImportProcess.cs
└── Runtime

MyPackage.EditorTests.asmdef 的标准格式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"name": "MyPackage.Editor.Tests",
"references": [
"MyPackage.Editor",
"MyPackage"
],
"optionalUnityReferences": [
"TestAssemblies"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": []
}

此处仅为测试用,所以可以稍作修改

1
2
3
4
5
6
7
8
// MyPackage.EditorTests.asmdef
{
"name": "EKKO测试.Editor.Tests",
"rootNamespace": "",
"references": [],
"autoReferenced": true,
}

1
2
3
4
5
6
7
8
// package.json 文件
{
"name": "com.ekko.ekko-package",
"displayName":"EKKO测试package",
"version": "1.0.1",
"author": "EKKO",
"description": "这是一个测试"
}

hh.png

2、编辑器开发

(1)创建编辑器

先写一个工具函数

1
2
3
4
5
6
7
8
9
public class MyTools
{
public static string GetParentPath(string path)
{
var str = path.Split("/");
path = path.Replace(str[str.Length - 1], "");
return path;
}
}

首先在代码中加上

1
[CreateAssetMenu(menuName = "EKKO/图片资源导入配置", fileName = "图片资源导入配置")]

此时在 Unity 中右键即可看到创建面板

注意:
点击创建后不要重命名

333.png

然后创建一个类继承自 ScriptableObject

1
2
3
4
public class MyTextureImportProcessSetting : ScriptableObject
{

}

注:

MonoBehaviour 是以组件形式挂在 GameObject 上的,而 ScriptableObject 则以 Assets 资源的形式存在的

类中写上要进行的设置,此处依据需要自定义

1
2
3
4
5
6
[Header("图片导入设置")]
[Space(10)]
// 以下自定义,此处仅为测试用
public TextureImporterType textureType = TextureImporterType.NormalMap;
public bool sRGB = true;
public bool readAble = true;

unity 编辑器开发需要引用 UnityEditor 命名空间,并且脚本需要继承 Editor 类,用于在 Unity 软件界面编辑自己的控件。

CustormEditor 一般与类 Editor 配合使用,以实现在 Inspector 面板中的自定义显示,使用时有几个注意点:

1、CustomEditor + typeof + 类名

2、自定义类是 Editor 的派生类

3、绘制自定义 UI 要重写 OnInspectorGUI 函数。此函数是虚函数

1
2
3
4
5
6
[CustomEditor(typeof(MyTextureImportProcessSetting))]
internal class TextureImportSetting : Editor
{
//target 被Inspector的对象。比如某个脚本
private MyTextureImportProcessSetting myTarget;
}

继承 UnityEditor 脚本的几个基本事件函数,详情查看官方文档

  • OnEnable() 在挂载目标脚本的物体被选中时调用。
  • OnInspectorGUI() 在 Inspector 面板绘制自定义 UI 的语句必须在这个函数中执行。
  • OnSceneGUI() 在场景视图中绘制自定义 UI 的语句必须在这个函数执行。
  • OnDestory() 在脚本被销毁时调用。

在 OnEnable()函数中添加

1
myTarget = target as MyTextureImportProcessSetting;

在 OnInspectorGUI()函数中添加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
base.OnInspectorGUI();

// GUILayout.Button()方法的返回值表示该按钮是否被点击,所以只需要if判断
if (GUILayout.Button("应用"))
{
var path = AssetDatabase.GetAssetPath(myTarget);
var files = Directory.GetFiles(MyTools.GetParentPath(path));

foreach (var file in files)
{
// 此处可扩展,将需要修改的纹理的后缀加到这里
if (dir.IndexOf(".jpg") > 0 || dir.IndexOf(".png") > 0 || dir.IndexOf(".tga") > 0)
{
AssetDatabase.ImportAsset(file);
}

}
}

(2) 使用设置

对上述简单应用实例脚本进行修改,将 OnPreprocessTexture()函数修改为:

1
2
3
4
5
6
7
8
9
10
11
TextureImporter impor = this.assetImporter as TextureImporter;
var parentPath = MyTools.GetParentPath(this.assetPath);
var settings = AssetDatabase.LoadAssetAtPath<MyTextureImportProcessSetting>( parentPath + "图片资源导入配置.asset");

if (settings)
{
Debug.Log("纹理资源: " + this.assetPath + " 使用了自定义的配置");
impor.textureType = settings .textureType;
impor.sRGBTexture = settings .sRGB;
impor.isReadable = settings .readAble;
}

3、效果展示

首先将图片拖入 Unity 工程下的文件夹中

444.png

当前图片属性设置如下

555.png

在该文件夹下创建一个编辑器

666.png

对编辑器进行设置并点击应用

777.png

可以看到图片属性已经被重新设置

888.png
999.png

此时控制台的打印如下

101010.png

四、扩展

以上功能仅限于与 “图片资源导入配置.asset” 处于同一文件夹中的纹理图片资源生效
如果要扩展,使得对该目录中的子文件夹里面的图片也生效,可以使用

1
2
3
4
5
6
7
// 获取path下的文件夹
var dirs = Directory.GetDirectories(path);

foreach (var dir in dirs)
{
AssetDatabase.ImportAsset(dir, ImportAssetOptions.ImportRecursive);
}

其中 ImportAssetOptions.ImportRecursive 功能为在导入一个文件时,同时导入其内容,详情见官方 API 介绍

五、项目源码

项目源码: GitHub 地址