当前位置:网站首页>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演示?
边栏推荐
- 竟然有一半的人不知道 for 与 foreach 的区别???
- 《论文阅读》Neural Approaches to Conversational AI(1)
- How to write test cases for test coupons?
- 正在运行的Kubernetes集群想要调整Pod的网段地址
- NPC Jincang was invited to participate in the "aerospace 706" I have an appointment with aerospace computer "national Partner Conference
- How to connect 5V serial port to 3.3V MCU serial port?
- 18 basic introduction to divider separator component of fleet tutorial (tutorial includes source code)
- 【全栈计划 —— 编程语言之C#】基础入门知识一文懂
- Explore cloud database of cloud services together
- Flet教程之 16 Tabs 选项卡控件 基础入门(教程含源码)
猜你喜欢

MATLAB实现Huffman编码译码含GUI界面

Programming examples of stm32f1 and stm32subeide -315m super regenerative wireless remote control module drive

Nuclear boat (I): when "male mothers" come into reality, can the biotechnology revolution liberate women?

Swiftui tutorial how to realize automatic scrolling function in 2 seconds

How much do you know about excel formula?

UP Meta—Web3.0世界创新型元宇宙金融协议

Poor math students who once dropped out of school won the fields award this year

.NET MAUI 性能提升

《通信软件开发与应用》课程结业报告

清华姚班程序员,网上征婚被骂?
随机推荐
千人规模互联网公司研发效能成功之路
R language Visual facet chart, hypothesis test, multivariable grouping t-test, visual multivariable grouping faceting boxplot, and add significance levels and jitter points
108. Network security penetration test - [privilege escalation 6] - [windows kernel overflow privilege escalation]
【系统设计】指标监控和告警系统
MATLAB实现Huffman编码译码含GUI界面
UP Meta—Web3.0世界创新型元宇宙金融协议
In depth learning autumn recruitment interview questions collection (1)
Common SQL statement collation: MySQL
《通信软件开发与应用》课程结业报告
防红域名生成的3种方法介绍
Flet教程之 14 ListTile 基础入门(教程含源码)
Sonar:Cognitive Complexity认知复杂度
本地navicat连接liunx下的oracle报权限不足
Superscalar processor design yaoyongbin Chapter 8 instruction emission excerpt
【滤波跟踪】基于matlab扩展卡尔曼滤波EKF和无迹卡尔曼滤波UKF比较【含Matlab源码 1933期】
R语言使用quantile函数计算评分值的分位数(20%、40%、60%、80%)、使用逻辑操作符将对应的分位区间(quantile)编码为分类值生成新的字段、strsplit函数将学生的名和姓拆分
清华姚班程序员,网上征婚被骂?
从工具升级为解决方案,有赞的新站位指向新价值
超标量处理器设计 姚永斌 第9章 指令执行 摘录
STM32 entry development uses IIC hardware timing to read and write AT24C08 (EEPROM)