前两天写了一个手动拖入通道来生成maskmap的工具: 在这个的基础上又研究了一下,实现了对于文件夹目录的一键maskmap生成!还做了一键修正贴图导入设置的功能。 留个小尾巴,等有空了可以再写一个自动生成对应的hdrp材质并贴图。不过不清楚第三方资源库的材质和模型的关系..可能还需要从prefab中extract....算了!再说! 更新下载地址👉TextureTool👈
资产相关类
有关Unity内的资源文件,有这样几个比较关键的类:
AssetDatabase
UnityEditor : An Interface for accessing assets and performing operations on assets.
AssetDatabase是对资产操作的主要接口,可以复制、删除、查询创建文件或文件夹。 e.g.
- 获取资产路径:
string path = AssetDatabase.GetAssetPath(metallic) ;
- 查找资产:
var texture2Ds = AssetDatabase.FindAssets ("t:Texture2D", paths);
第一个字符串是filter,可以使用name/label("l:")/type("t:")检索。其返回值是资产string形式的GUID,需要使用AssetDatabase.GUIDToAssetPath获得其路径,然后使用AssetDatabase.LoadAssetAtPath加载资产。
- 刷新资源列表
AssetDatabase.Refresh();
上一篇中,创建材质的方式是直接在对应路径写入文件,所以需要刷新并导入材质,让引擎识别新加入的文件。
AssetImporter
UnityEditor :Base class from which asset importers for specific asset types derive.
AssetImporter感觉是记录引擎识别资产的方式,可能与.meta文件相关? e.g.
- 利用userData防止重复编辑
var im = AssetImporter.GetAtPath (path); if (im.userData.Contains ("R2;")) continue; im.userData += "R2;";
- 转成对应类型的Importer(如TextureImporter),可对其进行详细设置的修改。 对于材质而言,常用的可以设置Texturetype(转normal),Tetureshapr(转cube),sRGBTexture等。 (靠 这不写个材质一键检查非srgb?) (写了写了)
DirectoryInfo
System.IO : Exposes instance methods for creating, moving, and enumerating through directories and subdirectories. This class cannot be inherited.
有关路径的操作,不只限于Editor。 e.g.
- 查询路径是否存在
// Check if the target directory exists, if not, create it. if (Directory.Exists(target.FullName) == false) { Directory.CreateDirectory(target.FullName); }
-
获得文件夹中文件的info
[FileSystemInfo][12][] fileSystemInfos = directoryInfo.GetFileSystemInfos();
获取路径和资产
如果已经有某个资产,需要获得它的路径,可以使用AssetDatabase.GetAssetPath()方法,比如上一篇用到的:
string path = AssetDatabase.GetAssetPath(metallic);
或者可以让用户选择要操作的文件夹路径:
private void SelectFolderPath() { GUILayout.BeginHorizontal(); { FolderPath = EditorGUILayout.TextField("Textures Folder", FolderPath); if (GUILayout.Button("...", GUILayout.Width(25))) { FolderPath = EditorUtility.OpenFolderPanel("Select a folder", "Assets", ""); } EditorGUIUtility.labelWidth = 0; } GUILayout.EndHorizontal(); }
EditorUtility.OpenFolderPanel()会打开一个选择文件夹的窗口,参数分别为[窗口名],[默认文件夹],[默认名]。上一篇中自定义保存用到了类似的EditorUtility.SaveFilePanel()。 这里学到了一个处理路径的小trick,可以只记录项目文件夹后的路径信息。定义此参数时就可以设定它的get/set方式:
private string _folderPath; protected string FolderPath { get { if (string.IsNullOrEmpty(_folderPath)) _folderPath = "Assets"; return _folderPath; } set { string pstr = Directory.GetParent(Application.dataPath).FullName; pstr = pstr.Replace("\\", "/"); if (value != null && value.Contains(pstr)) _folderPath = value.Replace(pstr + "/", ""); else _folderPath = value; } }
获得文件夹路径后,就可以通过AssetDatabase.FindAsset找到资源:
var texture2Ds = AssetDatabase.FindAssets ("t:Texture2D", new[]{FolderPath}); foreach (var textureguid in texture2Ds) { var texturepath = AssetDatabase.GUIDToAssetPath(textureguid); var texture = AssetDatabase.LoadAssetAtPath<Texture2D>(texturepath); //other operations HERE }
批量更改图片导入设置
unity不能自动识别从第三方网站下载的贴图类型,根据贴图存储的信息不同,需要进行不同的导入设置: 前面提到这些设置信息是存储在TextureImporter中的,只要从路径获取对应的Importer就可以了。注意修改后要SaveandReimport(),相当于setting面板点击apply。 目前还没有用到AssetBundle,之后如果需要就也会写啦! 实现代码如下:
private void FixSettings() { //获取文件夹下全部材质 var texture2Ds = AssetDatabase.FindAssets ("t:Texture2D", new[]{FolderPath}); foreach (var textureguid in texture2Ds) { var texturepath = AssetDatabase.GUIDToAssetPath(textureguid); //从路径获取importer var importer = AssetImporter.GetAtPath(texturepath) as TextureImporter; //只处理2D材质 if (importer.textureShape == TextureImporterShape.Texture2D) { //法线贴图,type设置为normal if (texturepath.Contains("_normal")||texturepath.Contains("_Normal")) { if (importer.textureType != TextureImporterType.NormalMap) { importer.textureType = TextureImporterType.NormalMap; importer.SaveAndReimport(); } continue; } //固有色贴图,开启sRGB if (texturepath.Contains("_albedo") || texturepath.Contains("_Albedo") || texturepath.Contains("_basecolor") || texturepath.Contains("_BaseColor") || texturepath.Contains("_baseColor")|| texturepath.Contains("_color") ) { if (!importer.sRGBTexture) { importer.sRGBTexture = true; importer.SaveAndReimport(); } continue; } //其他贴图,不开启sRGB else { if (importer.sRGBTexture) { importer.sRGBTexture = false; importer.SaveAndReimport(); } } }
批量生成mask map
利用了之前mapCreator的函数,还写了一个删除不需要的贴图的功能。其实这里还应该有一个弹出窗口警告不可撤销⚠但是我累了,,1.1再说,,, 有感而发:对于批处理工具而言,命名真的好重要哇。
private void BatchMask() { var texture2Ds = AssetDatabase.FindAssets ("t:Texture2D", new[]{FolderPath}); string currentTexture = ""; maptype = 0; bool hasM=false, hasAO=false,hasDM = false, hasR=false; foreach (var textureguid in texture2Ds) { var texturepath = AssetDatabase.GUIDToAssetPath(textureguid); //获取前缀前的材质名,用于识别贴图组 string exactname = Reverse(texturepath); exactname = exactname.Split(new char[]{'_'}, 2)[1]; exactname = Reverse(exactname); //当读入新的贴图名时,生成上一贴图组的maskmap if (exactname != currentTexture) { //当至少含有一张生成maskmap所需贴图时 if (hasM || hasR || hasDM || hasAO) { //将没有的贴图改为默认值,以免用到上一贴图组的贴图 if(!hasM) metallic = null; if(!hasAO) occlusion = null; if(!hasDM) detailmask = null; if(!hasR) smoothness = null; GenPictureAuto(); //如果需要删除hdrp不需要的贴图 if (deleteunused) { string deletepath; if (hasM) { deletepath = AssetDatabase.GetAssetPath(metallic); AssetDatabase.DeleteAsset(deletepath); } if (hasAO) { deletepath = AssetDatabase.GetAssetPath(occlusion); AssetDatabase.DeleteAsset(deletepath); } if (hasDM) { deletepath = AssetDatabase.GetAssetPath(detailmask); AssetDatabase.DeleteAsset(deletepath); } if (hasR) { deletepath = AssetDatabase.GetAssetPath(smoothness); AssetDatabase.DeleteAsset(deletepath); } AssetDatabase.Refresh(); } } //重置信息 hasM = false; hasR = false; hasDM = false; hasAO = false; currentTexture = exactname; } //若为金属度贴图 if (texturepath.Contains("_metallic") || texturepath.Contains("_Metallic")) { hasM = true; metallic = AssetDatabase.LoadAssetAtPath<Texture2D>(texturepath); } //若为ao else if(texturepath.Contains("_ao") || texturepath.Contains("_AO") || texturepath.Contains("_occlusion")|| texturepath.Contains("_Occlusion")) { hasAO = true; occlusion = AssetDatabase.LoadAssetAtPath<Texture2D>(texturepath); } //若为Smoothness else if(texturepath.Contains("_smoothness") || texturepath.Contains("_Smoothness")) { hasR = true; useRoughness = false; smoothness = AssetDatabase.LoadAssetAtPath<Texture2D>(texturepath); } //若为Roughness else if(texturepath.Contains("_Roughness") || texturepath.Contains("_roughness")) { hasR = true; useRoughness = true; smoothness = AssetDatabase.LoadAssetAtPath<Texture2D>(texturepath); } //若为DetailMask else if(texturepath.Contains("_DetailMask") || texturepath.Contains("_detailmask")) { hasDM = true; detailmask = AssetDatabase.LoadAssetAtPath<Texture2D>(texturepath); } } }
改变图片大小
加载图片,将其画在一张RenderTexture中,再新建一张Texture2D,从rt中读出来处理过的数据,再存进原路径中。 目前的这个功能还很不满意!用RT计算应该不是很合理的图像采样方法,放大缩小都会丢失很多细节... 不过还是先放一下~权当复习RT和图像写入了~
private void ResizeTextures()
{
var tempTexture = new Texture2D((int) resizeWH.x, (int) resizeWH.y, TextureFormat.ARGB32, false);
//获取文件夹下全部材质
var texture2Ds = AssetDatabase.FindAssets ("t:Texture2D", new[]{FolderPath});
foreach (var textureguid in texture2Ds)
{
var texturepath = AssetDatabase.GUIDToAssetPath(textureguid);
var texture = AssetDatabase.LoadAssetAtPath<Texture2D>(texturepath);
//若不需要重新调整大小,则跳过
Vector2 currentsize = new Vector2(texture.width, texture.height);
if(currentsize == resizeWH)
continue;
var rt = RenderTexture.GetTemporary((int) resizeWH.x, (int) resizeWH.y, 0, RenderTextureFormat.ARGB32);
rt.DiscardContents();
Graphics.Blit(texture,rt);
RenderTexture.active = rt;
tempTexture.ReadPixels(new Rect(0,0,rt.width,rt.height),0,0);
tempTexture.Apply();
if (texturepath.EndsWith(".png"))
{ //如果该材质含有tif标签,则跳过
var im = AssetImporter.GetAtPath (texturepath);
if (im.userData.Contains ("FromTIF;"))
continue;
File.WriteAllBytes(texturepath, tempTexture.EncodeToPNG());
}
else if (texturepath.EndsWith(".jpg"))
{
File.WriteAllBytes(texturepath, tempTexture.EncodeToJPG());
}
else if (texturepath.EndsWith(".tif"))
{
Debug.LogWarningFormat(texturepath + "has been saved as PNG.");
string newname = texturepath.Substring(0, texturepath.Length - 3) + "png";
File.WriteAllBytes(newname, tempTexture.EncodeToPNG());
//为tif转换的png图片增加标签
var im = AssetImporter.GetAtPath(newname);
im.userData += "FromTIF;";
}
RenderTexture.ReleaseTemporary(rt);
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}