当前位置:网站首页>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
- [shortest circuit] acwing1128 Messenger: Floyd shortest circuit
- EasyUI learn to organize notes
- 108.网络安全渗透测试—[权限提升篇6]—[Windows内核溢出提权]
- Talk about SOC startup (x) kernel startup pilot knowledge
- STM32F1与STM32CubeIDE编程实例-315M超再生无线遥控模块驱动
- Common SQL statement collation: MySQL
- [question] Compilation Principle
- 千人規模互聯網公司研發效能成功之路
- R language Visual facet chart, hypothesis test, multivariable grouping t-test, visual multivariable grouping faceting boxplot, and add significance levels and jitter points
猜你喜欢

【最短路】ACwing 1127. 香甜的黄油(堆优化的dijsktra或spfa)

What development models did you know during the interview? Just read this one

sql里,我想设置外键,为什么出现这个问题

In my limited software testing experience, a full-time summary of automation testing experience

Reasons for the failure of web side automation test

Automated testing framework

千人規模互聯網公司研發效能成功之路
![[texture feature extraction] LBP image texture feature extraction based on MATLAB local binary mode [including Matlab source code 1931]](/img/65/bf1d0f82878a49041e8c2b3a84bc15.png)
[texture feature extraction] LBP image texture feature extraction based on MATLAB local binary mode [including Matlab source code 1931]

相机标定(1): 单目相机标定及张正友标定基本原理

Talk about SOC startup (IX) adding a new board to uboot
随机推荐
R语言使用quantile函数计算评分值的分位数(20%、40%、60%、80%)、使用逻辑操作符将对应的分位区间(quantile)编码为分类值生成新的字段、strsplit函数将学生的名和姓拆分
【最短路】Acwing1128信使:floyd最短路
Excel公式知多少?
Zhou Yajin, a top safety scholar of Zhejiang University, is a curiosity driven activist
Complete collection of common error handling in MySQL installation
SwiftUI Swift 内功之如何在 Swift 中进行自动三角函数计算
The annual salary of general test is 15W, and the annual salary of test and development is 30w+. What is the difference between the two?
The Oracle message permission under the local Navicat connection liunx is insufficient
Suggestions on one-stop development of testing life
Use references
软件内部的定时炸弹:0-Day Log4Shell只是冰山一角
Electron adding SQLite database
大佬们有没有人遇到过 flink oracle cdc,读取一个没有更新操作的表,隔十几秒就重复读取
Poor math students who once dropped out of school won the fields award this year
STM32F1与STM32CubeIDE编程实例-MAX7219驱动8位7段数码管(基于SPI)
110. Network security penetration test - [privilege promotion 8] - [windows sqlserver xp_cmdshell stored procedure authorization]
Talk about SOC startup (IX) adding a new board to uboot
Flet tutorial 17 basic introduction to card components (tutorial includes source code)
Flet教程之 15 GridView 基础入门(教程含源码)
Swiftui swift internal skill: five skills of using opaque type in swift