当前位置:网站首页>Unity 贴图自动匹配材质工具 贴图自动添加到材质球工具 材质球匹配贴图工具 Substance Painter制作的贴图自动匹配材质球工具
Unity 贴图自动匹配材质工具 贴图自动添加到材质球工具 材质球匹配贴图工具 Substance Painter制作的贴图自动匹配材质球工具
2022-07-07 10:03:00 【唐沢】
强大的Unity编辑器扩展
有的同学可能会问:模型制作好,在模型设置里先解压贴图,再解压材质不就行了?
当然可以,不过现在解决的是模型没有贴图,贴图都是在SP里做的,导出来都是单独的贴图,不会直接和模型绑定
总之,你自己一个一个往材质球上贴也没啥问题,我是觉得贴的太痛苦了,来一个模型我得拿来贴贴贴…贴个der.
编辑器扩展就能解决很多手动的问题.
先看效果:
材质球会自动匹配贴图
匹配贴图时需要注意:
贴图名称必须是:模型名称_材质球名称_贴图类型
属性介绍
- 模型路径:把模型拖入会自动识别路径
- 贴图后缀:类似_Albedo或者_Occlusion,有的同学喜欢这样命名,AL,AO,所以开放出来自定义
- 导出材质球:模型存在的目录会自动创建Material文件夹,未解压材质的模型将会把材质解压到此文件夹
- 设置材质:根据模型与材质球的名称自动匹配贴图
SP导出流程:
文件 - 导出贴图 - 配置里需要这样命名
其中:
- $project是当前SP项目名称(用不到)
- $mesh是模型名称
- $textureSet是材质球名称
代码介绍:
属性这里可以修改默认后缀
[SerializeField]
public string m_Albedo = "_Albedo", m_Metallic = "_Metallic", m_NormalMap = "_Normal", m_HeightMap = "_Height", m_OcclusionMap = "_Occlusion";
这里设置名称规则:objName + “_” + mat.name + m_Albedo,可以自行修改
void setMaterialShader(string path)
{
Material mat = AssetDatabase.LoadAssetAtPath<Material>(path);
string[] allPath = GetObjPath("Texture2D");
for (int i = 0, len = allPath.Length; i < len; i++)
{
string filePath = AssetDatabase.GUIDToAssetPath(allPath[i]);
Texture2D t = AssetDatabase.LoadAssetAtPath<Texture2D>(filePath);
string objName = Path.GetFileName(modelPath);
objName = objName.Substring(0, objName.Length - 4);
if (t.name == objName + "_" + mat.name + m_Albedo)
{
mat.SetTexture(Albedo, t);
}
else if (t.name == objName + "_" + mat.name + m_HeightMap)
{
mat.SetTexture(HeightMap, t);
}
else if (t.name == objName + "_" + mat.name + m_Metallic)
{
mat.SetTexture(Metallic, t);
}
else if (t.name == objName + "_" + mat.name + m_NormalMap)
{
mat.SetTexture(NormalMap, t);
}
else if (t.name == objName + "_" + mat.name + m_OcclusionMap)
{
mat.SetTexture(OcclusionMap, t);
}
else
{
Debug.Log(mat.name+"材质球无法匹配:" + t.name);
}
}
}
完整代码:
这个代码继承EditorWindow
所以必须放在Editor文件夹下, 制作旋转门与相机控制器也是一样,都是用的编辑器扩展技术
using System.IO;
using UnityEngine;
using UnityEditor;
public class MatchinMaterial_Editor : EditorWindow
{
public string modelPath = "Assets";
public Rect modelRect;
public string Albedo = "_MainTex";
public string Metallic = "_MetallicGlossMap";
public string NormalMap = "_BumpMap";
public string HeightMap = "_ParallaxMap";
public string OcclusionMap = "_OcclusionMap";
private static MatchinMaterial_Editor _window;
[SerializeField]
public string m_Albedo = "_Albedo", m_Metallic = "_Metallic", m_NormalMap = "_Normal", m_HeightMap = "_Height", m_OcclusionMap = "_Occlusion";
[MenuItem("Tools/材质匹配")]
public static void showWindow()
{
Rect wr = new Rect(0, 0, 300, 300);
// true 表示不能停靠的
_window = (MatchinMaterial_Editor)GetWindowWithRect(typeof(MatchinMaterial_Editor), wr, true, "材质匹配");
_window.Show();
}
public void OnGUI()
{
EditorGUILayout.Space();
EditorGUILayout.LabelField("模型路径 (鼠标拖拽文件夹到这里)");
EditorGUILayout.Space();
GUI.SetNextControlName("input1");//设置下一个控件的名字
modelRect = EditorGUILayout.GetControlRect();
modelPath = EditorGUI.TextField(modelRect, modelPath);
EditorGUILayout.Space();
m_Albedo = EditorGUILayout.TextField("Albedo图片后缀", m_Albedo);
m_Metallic = EditorGUILayout.TextField("Metallic图片后缀", m_Metallic);
m_NormalMap = EditorGUILayout.TextField("NormalMap图片后缀", m_NormalMap);
m_HeightMap = EditorGUILayout.TextField("HeightMap图片后缀", m_HeightMap);
m_OcclusionMap = EditorGUILayout.TextField("OcclusionMap图片后缀", m_OcclusionMap);
DragFolder();
EditorGUILayout.Space();
// 导出材质
if (GUILayout.Button("导出材质球"))
{
ForEachModels();
}
EditorGUILayout.Space();
if (GUILayout.Button("设置材质"))
{
ForEachMaterials();
}
}
/// <summary>
/// 获得拖拽文件
/// </summary>
void DragFolder()
{
//鼠标位于当前窗口
if (mouseOverWindow == this)
{
//拖入窗口未松开鼠标
if (Event.current.type == EventType.DragUpdated)
{
DragAndDrop.visualMode = DragAndDropVisualMode.Generic;//改变鼠标外观
// 判断区域
if (modelRect.Contains(Event.current.mousePosition))
GUI.FocusControl("input1");
}
//拖入窗口并松开鼠标
else if (Event.current.type == EventType.DragExited)
{
string dragPath = string.Join("", DragAndDrop.paths);
// 判断区域
if (modelRect.Contains(Event.current.mousePosition))
this.modelPath = dragPath;
// 取消焦点(不然GUI不会刷新)
GUI.FocusControl(null);
}
}
}
/// <summary>
/// 导出材质
/// </summary>
void ForEachModels()
{
string[] allPath = AssetDatabase.FindAssets("t:GameObject", new string[] {
modelPath });
//Debug.Log("-- allPath: " + allPath.Length);
for (int i = 0, len = allPath.Length; i < len; i++)
{
string filePath = AssetDatabase.GUIDToAssetPath(allPath[i]);
// 设置模型
ExtractMaterialsFromFBX(filePath);
}
// 如果选取的是FBX模型文件
if (allPath.Length == 0)
{
if (Path.GetExtension(modelPath) == ".fbx")
{
ExtractMaterialsFromFBX(modelPath);
}
else
{
Debug.LogError("当前选择目录未找到FBX文件: " + this.modelPath);
}
}
}
/// <summary>
/// 导出材质球
/// </summary>
/// <param name="assetPath"></param>
public void ExtractMaterialsFromFBX(string assetPath)
{
// 材质目录
string materialFolder = Path.GetDirectoryName(assetPath) + "/Material";
//Debug.Log(assetPath);
// 如果不存在该文件夹则创建一个新的
if (!AssetDatabase.IsValidFolder(materialFolder))
AssetDatabase.CreateFolder(Path.GetDirectoryName(assetPath), "Material");
// 获取 assetPath 下所有资源。
Object[] assets = AssetDatabase.LoadAllAssetsAtPath(assetPath);
foreach (Object item in assets)
{
if (item.GetType() == typeof(Material))
{
string path = System.IO.Path.Combine(materialFolder, item.name) + ".mat";
// 为资源创建一个新的唯一路径。
path = AssetDatabase.GenerateUniqueAssetPath(path);
// 通过在导入资源(例如,FBX 文件)中提取外部资源,在对象(例如,材质)中创建此资源。
string value = AssetDatabase.ExtractAsset(item, path);
// 成功提取( 如果 Unity 已成功提取资源,则返回一个空字符串)
if (string.IsNullOrEmpty(value))
{
AssetDatabase.WriteImportSettingsIfDirty(assetPath);
AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUpdate);
Debug.Log(Path.GetFileName(assetPath) + " 的 Material 导出成功!!");
}
}
}
}
/// <summary>
/// 得到所有材质球
/// </summary>
void ForEachMaterials()
{
string[] allPath = GetObjPath("Material");
for (int i = 0, len = allPath.Length; i < len; i++)
{
string filePath = AssetDatabase.GUIDToAssetPath(allPath[i]);
setMaterialShader(filePath);
}
Debug.Log("Material Shader 设置完成, 一共: " + allPath.Length + "个");
}
void setMaterialShader(string path)
{
Material mat = AssetDatabase.LoadAssetAtPath<Material>(path);
string[] allPath = GetObjPath("Texture2D");
for (int i = 0, len = allPath.Length; i < len; i++)
{
string filePath = AssetDatabase.GUIDToAssetPath(allPath[i]);
Texture2D t = AssetDatabase.LoadAssetAtPath<Texture2D>(filePath);
string objName = Path.GetFileName(modelPath);
objName = objName.Substring(0, objName.Length - 4);
if (t.name == objName + "_" + mat.name + m_Albedo)
{
mat.SetTexture(Albedo, t);
}
else if (t.name == objName + "_" + mat.name + m_HeightMap)
{
mat.SetTexture(HeightMap, t);
}
else if (t.name == objName + "_" + mat.name + m_Metallic)
{
mat.SetTexture(Metallic, t);
}
else if (t.name == objName + "_" + mat.name + m_NormalMap)
{
mat.SetTexture(NormalMap, t);
}
else if (t.name == objName + "_" + mat.name + m_OcclusionMap)
{
mat.SetTexture(OcclusionMap, t);
}
else
{
Debug.Log(mat.name+"材质球无法匹配:" + t.name);
}
}
}
string[] GetObjPath(string mType)
{
//string path = Path.GetDirectoryName(modelPath) + "/Material";//得到此物体的文件目录,具体到Material文件
string path = Path.GetDirectoryName(modelPath);//得到此物体的文件目录
return AssetDatabase.FindAssets("t:"+ mType, new string[] {
path });//在这个文件下找"t:Material"这个文件
}
}
这个代码需要Demo演示?
边栏推荐
- Steps of redis installation and self startup configuration under CentOS system
- 一起探索云服务之云数据库
- CMU15445 (Fall 2019) 之 Project#2 - Hash Table 详解
- Automated testing framework
- Superscalar processor design yaoyongbin Chapter 8 instruction emission excerpt
- Electron adding SQLite database
- [system design] index monitoring and alarm system
- 相机标定(1): 单目相机标定及张正友标定基本原理
- STM32F1与STM32CubeIDE编程实例-315M超再生无线遥控模块驱动
- [filter tracking] strapdown inertial navigation simulation based on MATLAB [including Matlab source code 1935]
猜你喜欢
Mastering the new functions of swiftui 4 weatherkit and swift charts
相机标定(1): 单目相机标定及张正友标定基本原理
Talk about SOC startup (IX) adding a new board to uboot
powershell cs-UTF-16LE编码上线
Sonar:Cognitive Complexity认知复杂度
MATLAB實現Huffman編碼譯碼含GUI界面
Camera calibration (1): basic principles of monocular camera calibration and Zhang Zhengyou calibration
Improve application security through nonce field of play integrity API
Nuclear boat (I): when "male mothers" come into reality, can the biotechnology revolution liberate women?
浙江大学周亚金:“又破又立”的顶尖安全学者,好奇心驱动的行动派
随机推荐
大佬们有没有人遇到过 flink oracle cdc,读取一个没有更新操作的表,隔十几秒就重复读取
STM32 entry development write DS18B20 temperature sensor driver (read ambient temperature, support cascade)
There are so many factors that imprison you
Complete collection of common error handling in MySQL installation
从工具升级为解决方案,有赞的新站位指向新价值
HCIA复习整理
In depth learning autumn recruitment interview questions collection (1)
一度辍学的数学差生,获得今年菲尔兹奖
【系统设计】指标监控和告警系统
112.网络安全渗透测试—[权限提升篇10]—[Windows 2003 LPK.DDL劫持提权&msf本地提权]
【神经网络】卷积神经网络CNN【含Matlab源码 1932期】
Easyui学习整理笔记
Electron adding SQLite database
Zhou Yajin, a top safety scholar of Zhejiang University, is a curiosity driven activist
108.网络安全渗透测试—[权限提升篇6]—[Windows内核溢出提权]
Rationaldmis2022 advanced programming macro program
[extraction des caractéristiques de texture] extraction des caractéristiques de texture de l'image LBP basée sur le mode binaire local de Matlab [y compris le code source de Matlab 1931]
R language uses image of magick package_ Mosaic functions and images_ The flatten function stacks multiple pictures together to form a stack layers on top of each other
SwiftUI Swift 内功之如何在 Swift 中进行自动三角函数计算
[data clustering] realize data clustering analysis based on multiverse optimization DBSCAN with matlab code